जावास्क्रिप्ट जिज्ञासा का वादा करता है


96

जब मैं इस वादे को कॉल करता हूं, तो आउटपुट फ़ंक्शन कॉल के अनुक्रम के साथ मेल नहीं खाता है। .thenपहले आता है .catch, भले ही साथ वादा .thenके बाद बुलाया जा रहा था। उसका क्या कारण है?

const verifier = (a, b) =>
  new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));

verifier(3, 4)
  .then((response) => console.log("response: ", response))
  .catch((error) => console.log("error: ", error));

verifier(5, 4)
  .then((response) => console.log("response: ", response))
  .catch((error) => console.log("error: ", error));

उत्पादन

node promises.js
response: true
error: false

34
आपको वादों की स्वतंत्र श्रृंखलाओं के बीच समय पर भरोसा नहीं करना चाहिए।
बेरी जूल

जवाबों:


136

यह एक अच्छा सवाल है जिसकी तह तक जाना है।

जब आप ऐसा करते हैं:

verifier(3,4).then(...)

यह एक नया वादा देता है जिसे इवेंट लूप में एक और चक्र वापस करने की आवश्यकता होती है, इससे पहले कि नया अस्वीकृत वादा .catch()हैंडलर को चला सकता है। वह अतिरिक्त चक्र अगला क्रम देता है:

verifier(5,4).then(...)

.then()पिछली पंक्ति से पहले अपने हैंडलर को चलाने का मौका .catch()क्योंकि यह पहले से ही कतार में पहले .catch()से कतार में था और आइटम एफआईएफओ क्रम में कतार से चलाए जाते हैं।


ध्यान दें, कि यदि आप .then(f1, f2)फॉर्म का उपयोग करते हैं .then().catch(), तो यह तब चलता है जब आप इसकी अपेक्षा करते हैं, क्योंकि कोई अतिरिक्त वादा नहीं है और इस प्रकार कोई टिक नहीं है:

const verifier = (a, b) =>
  new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));

verifier(3, 4)
  .then((response) => console.log("response (3,4): ", response),
        (error) => console.log("error (3,4): ", error)
  );

verifier(5, 4)
  .then((response) => console.log("response (5,4): ", response))
  .catch((error) => console.log("error (5,4): ", error));

ध्यान दें, मैंने सभी संदेशों को भी लेबल किया है ताकि आप देख सकें कि verifier()वे किस कॉल से आते हैं जिससे आउटपुट को पढ़ना बहुत आसान हो जाता है।


ईएस 6 स्पेक कॉलबैक ऑर्डर और अधिक विस्तृत विवरण पर कल्पना

ईएस 6 कल्पना हमें बताती है कि "जॉब" का वादा करें (जैसा कि यह कॉलबैक से .then()या कॉल करता है .catch()) एफआईएफओ ऑर्डर में चलाए जाते हैं, जब उन्हें नौकरी की कतार में डाला जाता है। यह विशेष रूप से FIFO का नाम नहीं लेता है, लेकिन यह निर्दिष्ट करता है कि नई नौकरियां कतार के अंत में डाली जाती हैं और कतार की शुरुआत से नौकरियां चलती हैं। कि FIFO आदेश को लागू करता है।

PerformPromiseThen (जिसमें से कॉलबैक निष्पादित होता है .then()) EnqueueJob को बढ़ावा देगा जो कि हैंडलर को हल या अस्वीकार करने के लिए वास्तव में चलाने के लिए शेड्यूल किया जाता है। EnqueueJob निर्दिष्ट करता है कि लंबित कार्य को नौकरी की कतार में सबसे पीछे जोड़ा जाता है। तब NextJob ऑपरेशन कतार के सामने से आइटम खींचता है। यह वादा नौकरी कतार से नौकरियों की सेवा में FIFO आदेश सुनिश्चित करता है।

इसलिए, मूल प्रश्न में उदाहरण में, हम verifier(3,4)वादे के लिए कॉलबैक प्राप्त करते हैं और verifier(5,4)वादे को उस क्रम में नौकरी की कतार में डाल दिया जाता है, क्योंकि वे दोनों मूल वादे किए जाते हैं। फिर, जब दुभाषिया ईवेंट लूप में वापस जाता है, तो वह पहले verifier(3,4)काम चुनता है । यह वादा खारिज कर दिया गया है और इसमें उसके लिए कोई कॉलबैक नहीं है verifier(3,4).then(...)। तो, यह क्या करता है कि verifier(3,4).then(...)वापस आए वादे को अस्वीकार कर देता है और इससे verifier(3,4).then(...).catch(...)हैंडलर को जॉबक्यू में डाला जाता है।

फिर, यह इवेंट लूप पर वापस जाता है और अगली नौकरी जो इसे जॉब क्यू से खींचती है वह है verifier(5, 4)जॉब। इसका एक हल किया हुआ वादा और एक संकल्प हैंडलर है, इसलिए यह उस हैंडलर को बुलाता है। यह response (5,4):आउटपुट दिखाए जाने का कारण बनता है।

फिर, यह ईवेंट लूप पर वापस जाता है और अगली नौकरी जो इसे जॉब क्यू से खींचती है वह वह verifier(3,4).then(...).catch(...)कार्य है जहां यह चलता है और इसके कारण error (3,4)आउटपुट दिखाया जाता है।

ऐसा इसलिए है क्योंकि .catch()1 श्रृंखला .then()में 2 श्रृंखला की तुलना में इसकी श्रृंखला में एक वादा स्तर गहरा है जो आपके द्वारा रिपोर्ट किए गए आदेश का कारण बनता है। और, यह इसलिए है क्योंकि वादा श्रृंखला एक स्तर से अगले तक FIFO क्रम में नौकरी की कतार के माध्यम से निकाली जाती है, समकालिक रूप से नहीं।


निर्धारण स्तर के इस स्तर पर भरोसा करने के बारे में सामान्य सिफारिश

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


अधिक विशिष्ट होने के लिए, इस सटीक व्यवहार को वादों के विनिर्देश में कहीं भी प्रलेखित नहीं किया गया है जो इसे कार्यान्वयन विवरण बनाता है। आप दुभाषियों (जैसे। नोड बनाम एज बनाम फ़ायरफ़ॉक्स) के बीच या दुभाषियों के संस्करणों के बीच अलग-अलग व्यवहार प्राप्त कर सकते हैं (जैसे। नोड 12 बनाम नोड 14)। युक्ति केवल यह कहती है कि वादों को जैलगो कोड से बचने के लिए अतुल्य रूप से संसाधित किया जाता है (जिसे आईएमएचओ ने बीटीडब्लू को गुमराह किया था क्योंकि यह उन लोगों से प्रेरित था जो इस तरह के प्रश्न पूछ रहे थे जो संभावित अतुल्यकालिक कोड के समय पर निर्भर करना चाहते हैं)
स्लीमैन

@slebetman - क्या यह प्रलेखित नहीं है कि अलग-अलग वादों से वादा किए गए कॉलबैक को FIFO कहा जाता है, जब वे कतार में डाले गए थे और अगले टिक तक नहीं चल सकते थे? ऐसा लगता है कि FIFO ऑर्डर सभी के लिए आवश्यक है क्योंकि यहां .then()एक नया वादा वापस करना है जो खुद को भविष्य के टिक पर अतुल्यकालिक रूप से हल करना / अस्वीकार करना है जो इस आदेश की ओर जाता है। क्या आप किसी भी कार्यान्वयन के बारे में जानते हैं जो प्रतिस्पर्धा कॉलबैक के फीफो ऑर्डर का उपयोग नहीं करता है?
२०

3
@slebetman वादा / ए + इसे निर्दिष्ट नहीं करता है। ईएस 6 इसे निर्दिष्ट करता है। (ईएस 11 ने awaitहालांकि, के व्यवहार को बदल दिया )।
बरगी

ES6 कल्पना से कतार आदेश पर। PerformPromiseThenइससे पता चलेगा EnqueueJobकि प्रस्तावक या प्रस्ताव को अस्वीकार करने का तरीका निर्धारित किया जाता है। EnqueueJob निर्दिष्ट करता है कि लंबित कार्य को नौकरी की कतार में सबसे पीछे जोड़ा जाता है। फिर NextJob ऑपरेशन कतार के सामने से आइटम को खींचता है। यह वादा नौकरी कतार में FIFO आदेश सुनिश्चित करता है।
jfriend00

@Bergi awaitES11 में यह बदलाव क्या है ? एक लिंक पर्याप्त है। धन्यवाद!!
पेड्रो ए

49

Promise.resolve()
  .then(() => console.log('a1'))
  .then(() => console.log('a2'))
  .then(() => console.log('a3'))
Promise.resolve()
  .then(() => console.log('b1'))
  .then(() => console.log('b2'))
  .then(() => console.log('b3'))

आउटपुट a1, a2, a3, b1, b2, b3 के बजाय आपको a1, b1, a2, b2, a3, b3 समान कारण से दिखाई देंगे - प्रत्येक तब एक वादा वापस करता है और यह ईवेंट-लूप के अंत में जाता है कतार। इसलिए हम इस "वादे की दौड़" को देख सकते हैं। वही जब कुछ नेस्टेड वादे होते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.