टिप्पणियाँ
सबसे पहले, एक .then()
हैंडलर के अंदर वादों चल रहा है और .then()
कॉलबैक से उन वादों वापस नहीं एक पूरी तरह से नए स्वाधीन वादा अनुक्रम कि किसी भी तरह से माता पिता वादों साथ संबद्ध नहीं है बनाता है। आम तौर पर, यह एक बग है और, वास्तव में, कुछ वादे इंजन वास्तव में चेतावनी देते हैं जब आप ऐसा करते हैं क्योंकि यह लगभग वांछित व्यवहार नहीं होता है। एकमात्र ऐसा समय कभी ऐसा करना चाहेगा जब आप किसी प्रकार की आग कर रहे हों और ऑपरेशन भूल जाएं जहां आपको त्रुटियों की परवाह नहीं है और आपको बाकी दुनिया के साथ सिंक्रनाइज़ करने की परवाह नहीं है।
तो, आपके सभी Promise.resolve()
.then()
हैंडलर के अंदर वादे नए वादा श्रृंखला बनाते हैं जो मूल श्रृंखला से स्वतंत्र रूप से चलते हैं। आपके पास कोई दृढ़ व्यवहार नहीं है। यह समानांतर में चार AJAX कॉल लॉन्च करने जैसा है। आप नहीं जानते कि कौन सा पहला पूरा करेगा। अब, चूंकि Promise.resolve()
हैंडलर के अंदर आपके सभी कोड सिंक्रोनस होते हैं (क्योंकि यह वास्तविक दुनिया कोड नहीं है), तो आपको लगातार व्यवहार मिल सकता है, लेकिन यह वादे का डिज़ाइन बिंदु नहीं है इसलिए मैं अधिक समय नहीं व्यतीत करूंगा यह समझने की कोशिश कर रहा है कि कौन सी वादा श्रृंखला जो सिंक्रोनस कोड चलाती है केवल पहले खत्म होने जा रही है। असली दुनिया में, इससे कोई फर्क नहीं पड़ता क्योंकि अगर आदेश मायने रखता है, तो आप चीजों को मौके पर नहीं छोड़ेंगे।
सारांश
सभी .then()
संचालकों एसिंक्रोनस रूप से निष्पादन खत्म की वर्तमान धागा के बाद कहा जाता है (वादे/ए + कल्पना कहते हैं, जब जे एस इंजन वापस "मंच कोड" रिटर्न)। यह उन वादों के लिए भी सच है जो Promise.resolve().then(...)
जैसे समकालिक रूप से हल किए गए हैं।यह प्रोग्रामिंग स्थिरता के लिए किया जाता है ताकि .then()
हैंडलर को लगातार अतुल्यकालिक कहा जाता है चाहे कोई वादा तुरंत या बाद में हल हो जाए। यह कुछ समय की बग को रोकता है और कॉलिंग कोड को लगातार असीमित निष्पादन को देखने में आसान बनाता है।
कोई विनिर्देश नहीं है जो setTimeout()
बनाम निर्धारित .then()
हैंडलर के सापेक्ष क्रम को निर्धारित करता है यदि दोनों कतारबद्ध हैं और चलाने के लिए तैयार हैं। आपके कार्यान्वयन में, लंबित .then()
हैंडलर हमेशा लंबित setTimeout()
से पहले चलाया जाता है, लेकिन वादा/ए + स्पेक विनिर्देश कहता है कि यह निर्धारित नहीं है। यह कहता है कि .then()
हैंडलर को विभिन्न तरीकों से निर्धारित किया जा सकता है, जिनमें से कुछ setTimeout()
कॉल लंबित होने से पहले चलाए जाएंगे और इनमें से कुछ setTimeout()
कॉल लंबित होने के बाद चल सकते हैं। उदाहरण के लिए, वादे/ए + स्पेक .then()
हैंडलर को setImmediate()
के साथ निर्धारित करने की अनुमति देता है जो setTimeout()
कॉल लंबित होने से पहले या setTimeout()
के साथ चलाएगा जो setTimeout()
कॉल लंबित होने के बाद चलाएगा। तो, आपका कोड उस आदेश पर निर्भर नहीं होना चाहिए।
एकाधिक स्वतंत्र वादा श्रृंखलाओं में निष्पादन का अनुमानित आदेश नहीं है और आप किसी विशेष आदेश पर भरोसा नहीं कर सकते हैं। यह समानांतर में चार AJAX कॉलों को फायरिंग की तरह है जहां आप नहीं जानते कि कौन सा पहला पूरा करेगा।
यदि निष्पादन का आदेश महत्वपूर्ण है, तो उस दौड़ को न बनाएं जो मिनट कार्यान्वयन विवरण पर निर्भर है। इसके बजाय, एक विशेष निष्पादन आदेश को मजबूर करने के लिए वादे श्रृंखलाओं को लिंक करें।
आप आम तौर पर .then()
हैंडलर के भीतर स्वतंत्र वादे श्रृंखला बनाना नहीं चाहते हैं जो हैंडलर से वापस नहीं आते हैं। आग के दुर्लभ मामलों को छोड़कर यह आमतौर पर एक बग होता है और त्रुटि प्रबंधन के बिना भूल जाता है।
लाइन लाइन Analsysis
तक तो, यहाँ अपने कोड के एक विश्लेषण है। मैं लाइन नंबर जोड़ा गया है और यह आसान चर्चा करने के लिए बनाने के लिए खरोज साफ:
1 Promise.resolve('A').then(function (a) {
2 console.log(2, a);
3 return 'B';
4 }).then(function (a) {
5 Promise.resolve('C').then(function (a) {
6 console.log(7, a);
7 }).then(function (a) {
8 console.log(8, a);
9 });
10 console.log(3, a);
11 return a;
12 }).then(function (a) {
13 Promise.resolve('D').then(function (a) {
14 console.log(9, a);
15 }).then(function (a) {
16 console.log(10, a);
17 });
18 console.log(4, a);
19 }).then(function (a) {
20 console.log(5, a);
21 });
22
23 console.log(1);
24
25 setTimeout(function() {
26 console.log(6)
27 }, 0);
पंक्ति 1 एक वादा श्रृंखला शुरू होता है और इसे करने के लिए एक .then()
हैंडलर संलग्न। चूंकि Promise.resolve()
तुरंत हल हो जाता है, इसलिए वादा पुस्तकालय जावास्क्रिप्ट खत्म होने के इस धागे के बाद चलाने के लिए पहले .then()
हैंडलर शेड्यूल करेगा। वादे/ए + संगत वादा पुस्तकालयों में, सभी .then()
हैंडलर निष्पादन के वर्तमान धागे के बाद असीमित रूप से कहा जाता है और जब जेएस घटना लूप पर वापस जाता है। इसका मतलब यह है कि इस धागे में कोई अन्य सिंक्रोनस कोड जैसे कि console.log(1)
अगले दिखाई देगा जो आप देखते हैं।
अन्य सभी .then()
शीर्ष स्तर पर संचालकों (लाइनों 4, 12, 19) श्रृंखला पहले एक के बाद के बाद ही पहले एक अपनी बारी हो जाता है चलेंगे। वे अनिवार्य रूप से इस बिंदु पर कतारबद्ध हैं।
चूंकि setTimeout()
निष्पादन के प्रारंभिक धागे में भी है, यह चलाया जाता है और इस प्रकार टाइमर निर्धारित होता है।
यह तुल्यकालिक निष्पादन का अंत है। अब, जेएस इंजन घटना कतार में निर्धारित चीजें चलाना शुरू कर देता है।
जहां तक मुझे पता है, वहां कोई गारंटी नहीं है जो पहले setTimeout(fn, 0)
या .then()
हैंडलर है जो दोनों निष्पादन के इस धागे के ठीक बाद चलाने के लिए निर्धारित हैं। .then()
हैंडलर को "माइक्रो-वर्क्स" माना जाता है, इसलिए यह मुझे आश्चर्य नहीं करता कि वे setTimeout()
से पहले पहले भागते हैं। लेकिन, अगर आपको किसी विशेष आदेश की आवश्यकता है, तो आपको कोड लिखना चाहिए जो इस कार्यान्वयन के विस्तार पर निर्भर रहने के बजाय आदेश की गारंटी देता है।
वैसे भी, .then()
हैंडलर लाइन 1 पर परिभाषित है। इस प्रकार आप उस console.log(2, a)
से 2 "A"
आउटपुट देखते हैं।
इसके बाद, के बाद से पिछले .then()
हैंडलर एक सादे मान दिया, उस वादे का समाधान तो .then()
हैंडलर लाइन 4 रन पर परिभाषित माना जाता है। यहां वह जगह है जहां आप एक और स्वतंत्र वादा श्रृंखला बना रहे हैं और आमतौर पर एक बग है जो एक व्यवहार शुरू कर रहे हैं।
रेखा 5, एक नई वादा श्रृंखला बनाता है। यह प्रारंभिक वादा को हल करता है और उसके बाद निष्पादन के वर्तमान धागे को चलाने के लिए दो .then()
हैंडलर शेड्यूल करता है। निष्पादन के उस वर्तमान धागे में console.log(3, a)
लाइन 10 पर है इसलिए आप इसे अगले देखते हैं। फिर, निष्पादन का यह धागा खत्म हो जाता है और यह देखने के लिए शेड्यूलर पर वापस जाता है कि आगे क्या चलना है।
अब हमारे पास कतार में कई .then()
हैंडलर अगले भागने की प्रतीक्षा कर रहे हैं। वहाँ एक हम सिर्फ लाइन 5 पर निर्धारित है और वहाँ लाइन 12 उच्च स्तर श्रृंखला में अगले एक है आप लाइन 5 पर इस किया था, तो:
return Promise.resolve.then(...)
तो आप इन वादों को एक साथ जोड़ा और है | वे अनुक्रम में समन्वयित किया जाएगा। लेकिन, वादे मूल्य वापस नहीं लौटने के बाद, आपने एक पूरी नई वादा श्रृंखला शुरू की जो बाहरी, उच्च स्तर के वादे के साथ समन्वयित नहीं है। आपके विशेष मामले में, वादा शेड्यूलर अगले गहराई से घोंसला वाले .then()
हैंडलर को चलाने का निर्णय लेता है। मैं ईमानदारी से नहीं जानता कि यह विनिर्देश द्वारा, सम्मेलन द्वारा या केवल एक वादे इंजन बनाम एक कार्यान्वयन विवरण है। मैं कहूंगा कि अगर आदेश आपके लिए महत्वपूर्ण है, तो आपको पहले चलाने के लिए दौड़ जीतने पर भरोसा करने के बजाय किसी विशिष्ट क्रम में वादे को जोड़कर एक आदेश को मजबूर करना चाहिए।
वैसे भी, आपके मामले में, यह एक समय निर्धारण दौड़ है और इंजन आप चल रहे हैं भीतरी .then()
हैंडलर कि लाइन 5 पर अगले परिभाषित किया है भागने का फैसला किया है और इस तरह आप देख 7 "C"
लाइन 6 पर निर्दिष्ट। फिर यह कुछ भी नहीं देता है इसलिए इस वादे का हल मूल्य undefined
बन जाता है।
शेड्यूलर में वापस, यह .then()
हैंडलर लाइन 12 पर चलाता है। यह फिर से .then()
हैंडलर और लाइन 7 पर एक दौड़ है जो दौड़ने का इंतजार कर रहा है। मुझे नहीं पता कि यह एक दूसरे के ऊपर क्यों चुनता है यह कहने के अलावा कि यह अनिश्चित हो सकता है या प्रति वादे इंजन में भिन्न हो सकता है क्योंकि आदेश कोड द्वारा निर्दिष्ट नहीं है। किसी भी मामले में, .then()
हैंडलर लाइन 12 चलाने के लिए शुरू होता है। यह फिर से एक नई स्वतंत्र या अनसंक्रनाइज़ वादा श्रृंखला लाइन पिछले बनाता है। यह .then()
हैंडलर को फिर से शेड्यूल करता है और फिर आपको .then()
हैंडलर में सिंक्रोनस कोड से 4 "B"
मिलता है। सभी सिंक्रोनस कोड उस हैंडलर में अब किया जाता है, इसलिए यह अगले कार्य के लिए शेड्यूलर पर वापस जाता है।
अनुसूचक में वापस, यह लाइन 7 पर .then()
हैंडलर भागने का फैसला किया है और आप 8 undefined
मिलता है। वादा undefined
है क्योंकि पिछले .then()
उस श्रृंखला में हैंडलर कुछ भी वापस नहीं आया था, इस प्रकार इसका वापसी मूल्य undefined
था, इस प्रकार वह उस बिंदु पर वादे श्रृंखला का हल मूल्य है।
इस बिंदु पर, उत्पादन अब तक है:
1
2 "A"
3 "B"
7 "C"
4 "B"
8 undefined
फिर, सभी तुल्यकालिक कोड किया जाता है तो यह फिर से नियोजक को वापस चला जाता है और यह .then()
हैंडलर लाइन 13 पर परिभाषित भागने का फैसला किया । यह चलता है और आपको आउटपुट 9 "D"
मिलता है और फिर यह शेड्यूलर पर फिर से जाता है।
पहले नेस्ट Promise.resolve()
श्रृंखला के अनुरूप, अनुसूची अगले बाहरी .then()
हैंडलर लाइन 19 पर परिभाषित चलाने का निर्णय लेता। यह चलता है और आपको आउटपुट 5 undefined
मिलता है। यह फिर से undefined
है क्योंकि पिछले .then()
उस श्रृंखला में हैंडलर ने कोई मूल्य नहीं लौटाया, इस प्रकार वादे का हल मूल्य undefined
था।
इस बिंदु के रूप में, उत्पादन अब तक है:
1
2 "A"
3 "B"
7 "C"
4 "B"
8 undefined
9 "D"
5 undefined
इस बिंदु पर, केवल एक .then()
हैंडलर यह इतना चलाने के लिए अनुसूचित लाइन 15 पर परिभाषित एक रन है और आपको मिल आउटपुट 10 undefined
अगला।
फिर, अंत में, setTimeout()
चलाने के लिए हो जाता है और अंतिम आउटपुट है:
1
2 "A"
3 "B"
7 "C"
4 "B"
8 undefined
9 "D"
5 undefined
10 undefined
6
एक बिल्कुल इस में काम कर भविष्यवाणी करने के लिए प्रयास करने के लिए थे, तो वहाँ दो मुख्य सवाल होगा।
कैसे .then()
संचालकों प्राथमिकता के आधार पर बनाम setTimeout()
कॉल कि भी लंबित हैं लंबित हैं।
वादा इंजन कितने .then()
हैंडलर को प्राथमिकता देने का निर्णय लेता है जो सभी दौड़ने की प्रतीक्षा कर रहे हैं। इस कोड के साथ अपने परिणामों के अनुसार यह फीफो नहीं है।
पहला सवाल के लिए, मैं अगर यह विनिर्देश या वादा इंजन/जे एस इंजन में सिर्फ एक कार्यान्वयन विकल्प यहाँ प्रति है पता नहीं है, लेकिन कार्यान्वयन आप को सूचना दी से पहले सभी लंबित .then()
संचालकों को प्राथमिकता देने के लिए प्रकट होता है कोई भी setTimeout()
कॉल। आपका मामला एक अजीब बात है क्योंकि आपके पास .then()
हैंडलर निर्दिष्ट करने के अलावा कोई वास्तविक एसिंक एपीआई कॉल नहीं है। यदि आपके पास कोई एसिंक ऑपरेशन था जो वास्तव में इस वादे श्रृंखला की शुरुआत में निष्पादित करने के लिए कोई वास्तविक समय लेता था, तो setTimeout()
असली एसिंक ऑपरेशन पर .then()
हैंडलर से पहले निष्पादित करेगा क्योंकि असली एसिंक ऑपरेशन निष्पादित करने के लिए वास्तविक समय लेता है। तो, यह एक संक्षिप्त उदाहरण है और वास्तविक कोड के लिए सामान्य डिजाइन केस नहीं है।
दूसरे प्रश्न के लिए, मैंने कुछ चर्चा देखी है जो चर्चा करता है कि .then()
घोंसले के विभिन्न स्तरों पर हैंडलर को प्राथमिकता दी जानी चाहिए। मुझे नहीं पता कि उस चर्चा को किसी विनिर्देश में हल किया गया था या नहीं। मैं इस तरह से कोड करना पसंद करता हूं कि विस्तार का स्तर मुझसे कोई फर्क नहीं पड़ता। अगर मुझे अपने एसिंक ऑपरेशंस के आदेश की परवाह है, तो मैं आदेश को नियंत्रित करने के लिए अपने वादे श्रृंखलाओं को जोड़ता हूं और कार्यान्वयन के इस स्तर के विस्तार से मुझे किसी भी तरह प्रभावित नहीं होता है। अगर मुझे आदेश की परवाह नहीं है, तो मुझे इस आदेश की परवाह नहीं है कि फिर से कार्यान्वयन के स्तर का स्तर मुझे प्रभावित नहीं करता है। यहां तक कि अगर यह कुछ विनिर्देशों में था, तो ऐसा लगता है कि कई प्रकार के कार्यान्वयन (विभिन्न ब्राउज़रों, विभिन्न वादे इंजन) पर भरोसा नहीं किया जाना चाहिए, जब तक कि आप इसे हर जगह परीक्षण नहीं करते थे, जिसे आप चलाने जा रहे थे। इसलिए, जब आप अनसंक्रनाइज़ वादे श्रृंखला प्राप्त करते हैं तो मैं निष्पादन के विशिष्ट क्रम पर भरोसा नहीं करने की अनुशंसा करता हूं।
तुम बस की तरह इस (भीतरी वादों लौटने तो वे माता-पिता श्रृंखला में जुड़े हुए हैं) अपने सभी वादे जंजीरों को जोड़ने के द्वारा आदेश 100% नियत कर सकता है:
Promise.resolve('A').then(function (a) {
console.log(2, a);
return 'B';
}).then(function (a) {
var p = Promise.resolve('C').then(function (a) {
console.log(7, a);
}).then(function (a) {
console.log(8, a);
});
console.log(3, a);
// return this promise to chain to the parent promise
return p;
}).then(function (a) {
var p = Promise.resolve('D').then(function (a) {
console.log(9, a);
}).then(function (a) {
console.log(10, a);
});
console.log(4, a);
// return this promise to chain to the parent promise
return p;
}).then(function (a) {
console.log(5, a);
});
console.log(1);
setTimeout(function() {
console.log(6)
}, 0);
यह निम्न उत्पादन देता है क्रोम में:
1
2 "A"
3 "B"
7 "C"
8 undefined
4 undefined
9 "D"
10 undefined
5 undefined
6
और, क्योंकि वादे को सभी एक साथ बंधे हुए हैं, वादा आदेश सभी कोड द्वारा परिभाषित किया गया है। एक कार्यान्वयन विस्तार के रूप में छोड़ी गई एकमात्र चीज setTimeout()
का समय है, जैसा कि आपके उदाहरण में, .then()
हैंडलर लंबित होने के बाद अंतिम बार आता है।
संपादित करें:
Promises/A+ specification की परीक्षा पर, हम इस लगता है:
2.2.4 onFulfilled या onRejected तक निष्पादन संदर्भ ढेर केवल मंच कोड शामिल नहीं कहा जाना चाहिए। [3.1]।
....
3.1 यहाँ "मंच कोड" इंजन, पर्यावरण, और वादा कार्यान्वयन कोड का मतलब है। प्रैक्टिस में, यह आवश्यकता सुनिश्चित करती है कि पर पूर्ण और ऑनरजेक्टेड एसिंक्रोनिक रूप से निष्पादित करें, घटना लूप टर्न जिसमें बाद में कहा जाता है, और एक ताजा ढेर के साथ। यह या तो "मैक्रो-टास्क" तंत्र जैसे सेटटाइमआउट या सेट इमीडिएट, या "माइक्रो-टास्क" तंत्र जैसे उत्परिवर्तन ऑब्सर्वर या process.nextTick के साथ लागू किया जा सकता है। चूंकि वादा कार्यान्वयन को प्लेटफ़ॉर्म कोड माना जाता है, इसमें स्वयं को कार्य-शेड्यूलिंग कतार या "ट्रैम्पोलिन" हो सकता है जिसमें हैंडलर कहलाए जाते हैं।
यह कहना है कि .then()
संचालकों मंच कोड को कॉल स्टैक रिटर्न के बाद एसिंक्रोनस रूप से निष्पादित करना होगा, लेकिन कार्यान्वयन कैसे वास्तव में ऐसा करने के लिए करने के लिए पूरी तरह से छोड़ देता है कि क्या यह setTimeout()
या सूक्ष्म कार्य की तरह की तरह एक वृहद कार्य के साथ किया जाता है process.nextTick()
। तो, इस विनिर्देश के अनुसार, यह निर्धारित नहीं है और इस पर भरोसा नहीं किया जाना चाहिए।
मुझे ईएस 6 विनिर्देश में setTimeout()
के संबंध में मैक्रो-वर्क्स, माइक्रो-वर्क या वचन .then()
हैंडलर के बारे में कोई जानकारी नहीं मिली है।यह शायद आश्चर्यजनक नहीं है क्योंकि setTimeout()
स्वयं ईएस 6 विनिर्देश का हिस्सा नहीं है (यह एक मेजबान पर्यावरण समारोह है, न कि भाषा सुविधा है)।
मुझे इसे वापस करने के लिए कोई विशिष्टता नहीं मिली है, लेकिन इस प्रश्न के उत्तर Difference between microtask and macrotask within an event loop context बताते हैं कि मैक्रो-वर्क्स और माइक्रो-वर्क वाले ब्राउज़र में चीजें कैसे काम करती हैं।
एफवाईआई, यदि आप सूक्ष्म कार्यों और मैक्रो-कार्यों पर अधिक जानकारी चाहते हैं, तो यहां विषय पर एक दिलचस्प संदर्भ आलेख है: Tasks, microtasks, queues and schedules।
वचन 'वापसी' मूल्य से काम करते हैं वे जादुई नहीं हैं :) यदि आप 'फिर' से वापस नहीं आते हैं तो यह काम नहीं करेगा। यदि आप अपने कार्यों को जोड़ने के लिए 'वापसी' जोड़ते हैं तो यह आपकी अपेक्षा के अनुसार काम करेगा। इसके 100 डुप्लीकेट हैं - बस एक अच्छा इंगित करने के लिए बर्गि या जिफ्रेंड की प्रतीक्षा करेंगे। –
* "मैं निष्पादन आदेश 1 2 3 7 के बारे में उत्सुक हूं ... मूल्य 'ए', 'बी' नहीं ..." * फिर प्रश्न से अपर्याप्त जानकारी और कोड हटा दें। –
यदि आप स्पष्ट रूप से वादे से 'वापसी' नहीं करते हैं, तो यह असल में – Srle