2013-05-04 11 views
26

पर उत्तीर्ण नहीं होने का वादा किया गया है मुझे एक समस्या है कि एक वादे श्रृंखला के माध्यम से रिजेक्शन क्यों पारित नहीं किए जाते हैं और मुझे उम्मीद है कि कोई मुझे समझने में मदद करने में सक्षम होगा। मेरे लिए, वादे की एक श्रृंखला के लिए कार्यक्षमता को जोड़ना एक इरादा है जिसका अर्थ है कि मैं पूरा होने के मूल वचन के आधार पर हूं। व्याख्या करना मुश्किल है, इसलिए मुझे पहले अपनी समस्या का कोड उदाहरण दिखाएं। (नोट:। इस उदाहरण नोड और आस्थगित नोड मॉड्यूल उपयोग कर रहा है मैं डोजो 1.8.3 के साथ इस परीक्षण किया है और एक ही परिणाम था)अस्वीकार किए गए वादे

var d = require("deferred"); 

var d1 = d(); 

var promise1 = d1.promise.then(
    function(wins) { console.log('promise1 resolved'); return wins;}, 
    function(err) { console.log('promise1 rejected'); return err;}); 
var promise2 = promise1.then(
    function(wins) { console.log('promise2 resolved'); return wins;}, 
    function(err) { console.log('promise2 rejected'); return err;}); 
var promise3 = promise2.then(
    function(wins) { console.log('promise3 resolved'); return wins;}, 
    function(err) { console.log('promise3 rejected'); return err;}); 
d1.reject(new Error()); 
इस आपरेशन चलाने के परिणामों

इस उत्पादन है:

promise1 rejected 
promise2 resolved 
promise3 resolved 

ठीक है, मेरे लिए, यह परिणाम समझ में नहीं आता है। इस वादे श्रृंखला को जोड़कर, प्रत्येक व्यक्ति इस इरादे को लागू कर रहा है कि यह डी 1 के सफल समाधान पर निर्भर करेगा और परिणामस्वरूप श्रृंखला को पारित किया जा रहा है। अगर वादे 1 में वादा जीत मान प्राप्त नहीं करता है, लेकिन इसके बजाय इसके त्रुटि हैंडलर में एक त्रुटि मान हो जाता है, तो श्रृंखला में अगले वादे के लिए सफलता का कार्य कहां संभव है? अगले वादे के लिए सार्थक मूल्य पर कोई रास्ता नहीं हो सकता है क्योंकि इसे मूल्य नहीं मिला है।

मैं जो सोच रहा हूं उसका वर्णन करने का एक अलग तरीका यह है: तीन लोग, जॉन, अदरक और बॉब हैं। जॉन एक विजेट की दुकान का मालिक है। अदरक अपनी दुकान में आता है और मिश्रित रंगों के विगेट्स के बैग का अनुरोध करता है। उनके पास स्टॉक में नहीं है, इसलिए वह उन्हें वितरित करने के लिए अपने वितरक से अनुरोध भेजता है। इस बीच, वह अदरक को बारिश की जांच देता है जिसमें कहा गया है कि उसे विजेट के बैग का बकाया है। बॉब को पता चला कि अदरक को विजेट मिल रहा है और अनुरोध है कि जब वह उनके साथ हो तो नीली विजेट प्राप्त करेगी। वह सहमत है और उसे एक नोट बताती है कि वह करेगी। अब, जॉन के वितरक को उनकी आपूर्ति में कोई विजेट नहीं मिल रहा है और निर्माता उन्हें और अधिक नहीं बनाता है, इसलिए वे जॉन को सूचित करते हैं, जो बदले में अदरक को सूचित करता है कि वह विजेट नहीं प्राप्त कर सकती है। बॉब को अदरक से नीला विजेट कैसे प्राप्त हो सकता है जब खुद को नहीं मिला?

इस मुद्दे पर मेरे पास तीसरा और यथार्थवादी परिप्रेक्ष्य है। मान लें कि मेरे पास दो मान हैं जिन्हें मैं डेटाबेस में अपडेट करना चाहता हूं। एक दूसरे की आईडी पर निर्भर है, लेकिन मैं तब तक आईडी नहीं प्राप्त कर सकता जब तक कि मैंने इसे पहले ही डेटाबेस में डाला नहीं है और नतीजा प्राप्त किया है। उस पर, पहला डालने डेटाबेस से एक क्वेरी पर निर्भर है। डेटाबेस उन रिटर्न वादे को कॉल करता है जिनका उपयोग मैं दो कॉलों को अनुक्रम में श्रृंखलाबद्ध करने के लिए करता हूं।

var promise = db.query({parent_id: value}); 
promise.then(function(query_result) { 
    var first_value = { 
     parent_id: query_result[0].parent_id 
    } 
    var promise = db.put(first_value); 
    promise.then(function(first_value_result) { 
     var second_value = { 
      reference_to_first_value_id: first_value_result.id 
     } 
     var promise = db.put(second_value); 
     promise.then(function(second_value_result) { 
      values_successfully_entered(); 
     }, function(err) { return err }); 
    }, function(err) { return err }); 
}, function(err) { return err }); 

अब, इस स्थिति में, यदि db.query विफल हो गया है, तो यह पहले के त्रुटि कार्य को कॉल करेगा। लेकिन फिर यह अगले वादे के सफल कार्य को बुलाएगा। जबकि वह वादा पहले मूल्य के परिणामों की अपेक्षा कर रहा है, इसके बजाय इसके त्रुटि हैंडलर फ़ंक्शन से त्रुटि संदेश प्राप्त होगा।

तो, मेरा सवाल यह है कि, अगर मुझे अपने सफल कार्य में त्रुटियों का परीक्षण करना है तो मुझे एक त्रुटि सौंपने का फ़ंक्शन क्यों होगा?

इसकी लंबाई के लिए खेद है। मैं बस यह नहीं जानता था कि इसे कैसे एक और तरीके से समझाया जाए।

अद्यतन और सुधार

(नोट:।। मैं एक प्रतिक्रिया मैं एक बार कुछ टिप्पणी करने के लिए किया था, तो किसी को भी मेरी प्रतिक्रिया पर टिप्पणी की, उनकी टिप्पणी संदर्भ से बाहर लग सकता है तो अब हटा दिया है कि मैं इसे हटा दिया क्षमा करें इसके लिए, मैं इसे यथासंभव छोटा रखने की कोशिश कर रहा हूं।)

उत्तर देने वाले सभी को धन्यवाद। मैं सबसे पहले अपने प्रश्न को इतनी खराब लिखने के लिए माफ़ी मांगना चाहता हूं, खासकर मेरे छद्म कोड। मैं इसे कम रखने की कोशिश में थोड़ा आक्रामक था।

बर्गी की प्रतिक्रिया के लिए धन्यवाद, मुझे लगता है कि मुझे अपने तर्क में त्रुटि मिली है। मुझे लगता है कि मैंने एक और मुद्दा अनदेखा कर दिया है जो समस्या का कारण बन रहा था। यह संभवतः वादे श्रृंखला को अलग-अलग तरीके से काम कर रहा है जैसा मैंने सोचा था। मैं अभी भी अपने कोड के विभिन्न तत्वों का परीक्षण कर रहा हूं, इसलिए मैं यह देखने के लिए एक उचित प्रश्न भी नहीं बना सकता कि मैं अभी क्या गलत कर रहा हूं। हालांकि मैं आपको सभी को अपडेट करना चाहता था और आपकी मदद के लिए धन्यवाद।

+1

आप किस संस्करण का उपयोग कर रहे हैं? यह 0.10.0 पर मेरे लिए 'अस्वीकृत' 3 बार प्रदर्शित करता है और 0.6.3 स्थगित करता है। – loganfsmyth

+0

यह मेरे लिए भी काम करता है और नोड 0.8.3 और डिफर्ड 0.6.3 https://gist.github.com/Stuk/694b2377057453aa6946 –

उत्तर

25

मेरे लिए, यह परिणाम समझ में नहीं आता है। इस वादे श्रृंखला के लिए संलग्न से, प्रत्येक तो आशय जिसका अर्थ है कि यह d1 और एक परिणाम के सफल संकल्प पर निर्भर श्रृंखला के नीचे पारित किया जा रहा हो जाएगा

नहीं। क्या आप का वर्णन कर रहे हैं एक श्रृंखला नहीं है, लेकिन बस सभी कॉलबैक को d1 पर संलग्न करें। फिर भी, यदि आप then के साथ कुछ श्रृंखला बनाना चाहते हैं, तो promise2 का परिणाम promise1के संकल्प पर निर्भर करता है और then कॉलबैक ने को कैसे संभाला।

डॉक्स राज्य:

कॉलबैक (रों) का परिणाम के लिए एक नया वादा देता है।

.then विधि आमतौर पर Promises/A specification (या यहां तक ​​कि सख्त Promsises/A+ one) के संदर्भ में देखा जाता है। इसका मतलब है कि कॉलबैक शेल रिटर्न वादे करता है जिसे promise2 का संकल्प बनने के लिए समेकित किया जाएगा, और यदि कोई सफलता/त्रुटि हैंडलर नहीं है तो संबंधित परिणाम सीधे promise2 पर पारित किया जाएगा - ताकि आप आसानी से प्रचारक को को छोड़ सकें त्रुटि।

फिर भी, यदि त्रुटि संभालती है, परिणामी promise2 को निश्चित रूप से देखा जाता है और उस मान के साथ पूरा किया जाएगा। यदि आप इसे नहीं चाहते हैं, तो आपको re-throw त्रुटि की आवश्यकता होगी, बस एक कोशिश-पकड़ खंड में। वैकल्पिक रूप से आप हैंडलर से एक (टू-बी-) खारिज किए गए वादे को वापस कर सकते हैं। सुनिश्चित नहीं हैं कि डोजो तरह से अस्वीकार करने के लिए है, लेकिन:

var d1 = d(); 

var promise1 = d1.promise.then(
    function(wins) { console.log('promise1 resolved'); return wins;}, 
    function(err) { console.log('promise1 rejected'); throw err;}); 
var promise2 = promise1.then(
    function(wins) { console.log('promise2 resolved'); return wins;}, 
    function(err) { console.log('promise2 rejected'); throw err;}); 
var promise3 = promise2.then(
    function(wins) { console.log('promise3 resolved'); return wins;}, 
    function(err) { console.log('promise3 rejected'); throw err;}); 
d1.reject(new Error()); 

कैसे है बॉब जब किसी भी खुद को नहीं मिला अदरक से एक नीले विजेट प्राप्त करने में सक्षम?

वह सक्षम नहीं होना चाहिए। यदि कोई त्रुटि हैंडलर नहीं हैं, तो वह केवल अदरक से संदेश ((वितरक से) से) को समझेंगे) कि कोई विजेट शेष नहीं है। फिर भी, अगर अदरक उस मामले के लिए एक त्रुटि हैंडलर सेट करता है, तो वह अभी भी जॉन या उसके वितरक में छोड़े गए कोई नीले रंग वाले नहीं होने पर बॉब को अपने ही ढेर से एक हरा देकर अपना वादा पूरा कर सकता है।

हैंडलर में return err मेटाफ़र में आपकी त्रुटि कॉलबैक का अनुवाद करने के लिए बस यह कहने की तरह होगा कि "अगर कोई विजेट शेष नहीं है, तो बस उसे नोट दें कि कोई भी नहीं छोड़ा गया है - यह वांछित विजेट जैसा अच्छा है" ।

डेटाबेस स्थिति में, यदि डीबी।क्वेरी विफल रही, यह पहले के

... का अर्थ होगा कि त्रुटि का प्रबंधन किया जाएगा। यदि आप ऐसा नहीं करते हैं, तो बस त्रुटि कॉलबैक को छोड़ दें। बीटीडब्ल्यू, आपकी सफलता कॉलबैक return वे जो वादे बना रहे हैं, वे नहीं हैं, इसलिए वे काफी बेकार लगते हैं। सही होगा:

var promise = db.query({parent_id: value}); 
promise.then(function(query_result) { 
    var first_value = { 
     parent_id: query_result[0].parent_id 
    } 
    var promise = db.put(first_value); 
    return promise.then(function(first_value_result) { 
     var second_value = { 
      reference_to_first_value_id: first_value_result.id 
     } 
     var promise = db.put(second_value); 
     return promise.then(function(second_value_result) { 
      return values_successfully_entered(); 
     }); 
    }); 
}); 

या, जब से तुम पिछले कॉलबैक से पहुँच परिणाम मूल्यों के बंद होने की जरूरत नहीं है, यहां तक ​​कि:

db.query({parent_id: value}).then(function(query_result) { 
    return db.put({ 
     parent_id: query_result[0].parent_id 
    }); 
}).then(function(first_value_result) { 
    return db.put({ 
     reference_to_first_value_id: first_value_result.id 
    }); 
}.then(values_successfully_entered); 
+3

$ q के साथ angularJS का उपयोग करते समय, फेंक कीवर्ड $ q.reject (अं)। – Toilal

+3

@ Toilal की टिप्पणी को साफ़ करने के लिए, * फेंक दिया * * फेंकने के लिए प्रतिस्थापन * 'q.reject (err) वापसी 'है। 'फेंक', मुझे विश्वास है, अभी भी काम करते हैं; यह बहुत धीमा है। – Malvolio

1

@Jordan सबसे पहले के रूप में टिप्पणीकर्ताओं बताया गया है, जब आस्थगित lib का उपयोग कर, अपना पहला उदाहरण निश्चित रूप से आप उम्मीद परिणाम पैदा करता है:

promise1 rejected 
promise2 rejected 
promise3 rejected 

दूसरे, भले ही यह उत्पादन सुझाव का उत्पादन होता है, यह अपने दूसरे टुकड़ा, के निष्पादन के प्रवाह को प्रभावित नहीं करेगा जो मैं सा अलग सा, की तरह अधिक:

promise.then(function(first_value) { 
    console.log('promise1 resolved'); 
    var promise = db.put(first_value); 
    promise.then(function (second_value) { 
     console.log('promise2 resolved'); 
     var promise = db.put(second_value); 
     promise.then(
      function (wins) { console.log('promise3 resolved'); }, 
      function (err) { console.log('promise3 rejected'); return err; }); 
    }, function (err) { console.log('promise2 rejected'); return err;}); 
}, function (err) { console.log('promise1 rejected'); return err}); 

और है कि, पहली वादा के मामले में अस्वीकार कर दिए जाने होगा सिर्फ उत्पादन:

promise1 rejected 

हालांकि (सबसे दिलचस्प हिस्सा के लिए हो रही) भले ही आस्थगित पुस्तकालय निश्चित रूप से 3 x rejected लौटाता है, अन्य वादा पुस्तकालयों में से अधिकांश 1 x rejected, 2 x resolved लौटाएंगे (जो अनुमान लगाता है कि आपको इसके परिणामस्वरूप कुछ अन्य वादा पुस्तकालय का उपयोग करके परिणाम मिलते हैं)।

अतिरिक्त रूप से भ्रमित करने वाला, अन्य पुस्तकालय उनके व्यवहार के साथ अधिक सही हैं। मुझे समझाने दो।

सिंक में "वादा अस्वीकृति" के विश्व समकक्ष throw है। तो अर्थात्, async deferred.reject(new Error()) सिंक में throw new Error() के बराबर है। अपने उदाहरण में आप अपने सिंक कॉलबैक में त्रुटियों को फेंक नहीं रहे हैं, तो आप उन्हें वापस लौट रहे हैं, इसलिए आप सफल प्रवाह पर स्विच करते हुए सफल प्रवाह पर स्विच करते हैं। यकीन है कि अस्वीकृति आगे पारित हो जाता है बनाने के लिए, आप अपने त्रुटियों को फिर से हटाने की आवश्यकता:

function (err) { console.log('promise1 rejected'); throw err; }); 

तो अब सवाल है, क्यों आस्थगित पुस्तकालय त्रुटि अस्वीकृति के रूप में वापस ले गया?

इसके कारण, स्थगित कार्यों में अस्वीकृति थोड़ा अलग है। स्थगित lib में नियम है: त्रुटि के उदाहरण के साथ हल होने पर वादा अस्वीकार कर दिया जाता है, इसलिए यदि आप deferred.resolve(new Error()) करते हैं तो यह deferred.reject(new Error()) के रूप में कार्य करेगा, और यदि आप deferred.reject(notAnError) करने का प्रयास करते हैं तो यह एक अपवाद फेंक देगा, वह वादा कर सकता है केवल त्रुटि के उदाहरण के साथ खारिज कर दिया जाना चाहिए। यह स्पष्ट करता है कि then कॉलबैक से त्रुटि क्यों वापस आती है।

स्थगित तर्क के पीछे कुछ मान्य तर्क है, लेकिन फिर भी यह throw जावास्क्रिप्ट में काम करता है, और इसके कारण यह व्यवहार स्थगित संस्करण v0.7 के साथ बदलने के लिए निर्धारित है।

संक्षिप्त सारांश:

भ्रम और अप्रत्याशित परिणाम से बचने के लिए सिर्फ अच्छा अभ्यास नियमों का पालन करें:

  1. हमेशा एक त्रुटि उदाहरणों के साथ अपने वादे को अस्वीकार (सिंक दुनिया है, जहां मूल्य फेंकने के नियमों का पालन है कि नहीं है एक त्रुटि को एक बुरा अभ्यास माना जाता है)।
  2. द्वारा सिंक कॉलबैक से अस्वीकार त्रुटियों को फेंकना (उन्हें लौटने से अस्वीकृति की गारंटी नहीं है)।

उपरोक्त का पालन करते हुए, आपको स्थगित और अन्य लोकप्रिय वादे पुस्तकालयों दोनों में लगातार और अपेक्षित परिणाम मिलेंगे।

0

उपयोग वादा के प्रत्येक स्तर पर त्रुटियों को लपेट सकता है।

class TraceError extends Error { 
    constructor(message, ...causes) { 
    super(message); 

    const stack = Object.getOwnPropertyDescriptor(this, 'stack'); 

    Object.defineProperty(this, 'stack', { 
     get:() => { 
     const stacktrace = stack.get.call(this); 
     let causeStacktrace = ''; 

     for (const cause of causes) { 
      if (cause.sourceStack) { // trigger lookup 
      causeStacktrace += `\n${cause.sourceStack}`; 
      } else if (cause instanceof Error) { 
      causeStacktrace += `\n${cause.stack}`; 
      } else { 
      try { 
       const json = JSON.stringify(cause, null, 2); 
       causeStacktrace += `\n${json.split('\n').join('\n ')}`; 
      } catch (e) { 
       causeStacktrace += `\n${cause}`; 
       // ignore 
      } 
      } 
     } 

     causeStacktrace = causeStacktrace.split('\n').join('\n '); 

     return stacktrace + causeStacktrace; 
     } 
    }); 

    // access first error 
    Object.defineProperty(this, 'cause', {value:() => causes[0], enumerable: false, writable: false}); 

    // untested; access cause stack with error.causes() 
    Object.defineProperty(this, 'causes', {value:() => causes, enumerable: false, writable: false}); 
    } 
} 

प्रयोग

throw new TraceError('Could not set status', srcError, ...otherErrors); 

आउटपुट

कार्य: मैं TraceError में त्रुटियों श्रृंखलित

TraceError#cause - first error 
TraceError#causes - list of chained errors 
संबंधित मुद्दे