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


99

जैसा कि मैं समझता हूं कि एक वादा कुछ ऐसा है जो हल कर सकता है () या अस्वीकार () लेकिन मुझे यह पता लगाने के लिए आश्चर्य हुआ कि वादा में कोड एक संकल्प या अस्वीकार के बाद निष्पादित करना जारी है।

मैंने संकल्प किया या बाहर निकलने या वापसी का एक async-अनुकूल संस्करण होने को अस्वीकार कर दिया, जो सभी तत्काल कार्य निष्पादन को रोक देगा।

क्या कोई इसके पीछे सोचा समझा सकता है कि निम्न उदाहरण कभी-कभी एक समाधान कॉल के बाद कंसोल.लॉग दिखाता है:

var call = function() {
    return new Promise(function(resolve, reject) {
        resolve();
        console.log("Doing more stuff, should not be visible after a resolve!");
    });
};

call().then(function() {
    console.log("resolved");
});

jsbin


13
वाजिब सवाल, लेकिन फिर, जेएस एक के बाद एक बयान पर अमल करता है, जैसे आप उसे बताते हैं। resolve()जेएस कंट्रोल स्टेटमेंट नहीं है जो जादुई तरीके से असर करता है return, यह सिर्फ एक फंक्शन कॉल है, और हां, इसके बाद भी निष्पादन जारी रहता है।

यह एक अच्छा सवाल है, और सभी प्रतिक्रियाओं को पढ़ने के बाद भी, मैं सर्वोत्तम प्रथाओं के बारे में निश्चित नहीं हूं ...
गेब्रियल ग्लेन

मुझे लगता है कि गलतफहमी उसी से होती है, जिसे आप संकल्प के साथ समाप्त कर रहे हैं (): वादे को हल करने के बाद ही आईएस हल हो जाता है (), लेकिन जैसा कि पहले ही दूसरों द्वारा कहा गया है, इसका मतलब यह नहीं है कि वचन को समाप्त करने वाले फ़ंक्शन ने इसे समाप्त कर दिया था कर्तव्य भी, इसलिए यह तब तक जारी रहता है जब तक यह "सामान्य" समाप्ति तक नहीं पहुंच जाता।
ग्यूसेप बर्टोन

जवाबों:


146

जावास्क्रिप्ट में "रन टू पूरा" की अवधारणा है । जब तक कोई त्रुटि नहीं डाली जाती है, तब तक एक फ़ंक्शन को निष्पादित किया जाता है जब तक कि एक returnबयान या उसके अंत तक नहीं पहुंच जाता है। फ़ंक्शन के बाहर अन्य कोड उस के साथ हस्तक्षेप नहीं कर सकते (जब तक, फिर से, एक त्रुटि फेंक दी जाती है)।

यदि आप resolve()अपने आरंभिक कार्य से बाहर निकलना चाहते हैं , तो आपको इसे पूर्व निर्धारित करना होगा return:

return new Promise(function(resolve, reject) {
    return resolve();
    console.log("Not doing more stuff after a return statement");
});

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

3
@ अलनीतक resolveखुद अतुल्यकालिक नहीं है, यह पूरी तरह से सिंक्रोनस है। हालांकि कड़ाई से ईएस 6 एपीआई का उपयोग करना यह अवलोकनीय नहीं है कि यह सिंक्रोनस या एसिंक्रोनस है।
एसेलीजा

1
@Esailija ठीक है, शायद मैं अस्पष्ट था। कुछ लोगों का मानना ​​है कि कॉलिंग के resolveपरिणामस्वरूप किसी भी पंजीकृत कॉलबैक को तुरंत लागू किया जाएगा जैसे कि वे वर्तमान कॉल स्टैक का हिस्सा हैं। यह सच नहीं है, इसके बजाय यह केवल कॉलबैक को कतार में रखता है (और आप सही हैं, यह async नहीं है, लेकिन यह बस अपनी बात करता है और तुरंत समाप्त हो जाता है)
Alnitak

@Alnitak: मैं समझता हूं कि आप क्या कह रहे हैं। मैंने इसे केवल इस रूप में व्याख्या किया है कि console.logइसके बजाय शो क्यों करता है इसके बजाय उस क्रम में क्यों दिखाई देता है। अब तक, मैं क्या resolveऔर कैसे वादे करता हूं, इस सवाल की व्याख्या करने के लिए कितना अप्रासंगिक है। लेकिन निश्चित रूप से वादों के संदर्भ में जानना अभी भी महत्वपूर्ण है। उन कारणों में से एक जो मैंने आपके उत्तर को छोड़ दिया :)
फेलिक्स क्लिंग

9
@ बर्गी, अपने संपादन में, आप कहते हैं "वापसी समाधान ();" जो असामान्य लगता है। अपने आप को यह समझाने के लिए कि वहां कुछ भी महत्व नहीं है, मुझे प्रलेखन पढ़ना था और यह देखना था कि (1) संकल्प () परिणाम के कुछ भी वापस करने के लिए प्रकट नहीं होता है, और (2) आरंभीकरण कॉलबैक का वापसी मूल्य नहीं है उपयोग में आना। क्या यह स्पष्ट नहीं होगा कि "समाधान (); वापसी;" जिससे इस विकर्षण से बचा जा सके?
डॉन हैच

19

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

इसलिए जब आप आह्वान करते हैं resolveतो कॉलबैक पंक्तिबद्ध होता है , और resolve()कॉल के बाद किसी भी कोड के साथ फ़ंक्शन निष्पादन तुरंत होता है ।

केवल एक बार जेएस ईवेंट लूप वापस दिए जाने के बाद कॉलबैक को कतार से हटाया जा सकता है और वास्तव में लागू किया जा सकता है।


1
कॉलबैक कतार में A + चश्मा या ES6 में प्रलेखित है?
Thefourtheye

5
@thefourtheye: इवेंट लूप विनिर्देश वास्तव में अब HTML5 का हिस्सा है । ईएस 6 नामक एक आंतरिक विधि को परिभाषित करता है EnqueueJob, जिसे द्वारा लागू किया जाता है .then
फेलिक्स क्लिंग

@thefourtheye: वास्तव में, ES6 भी कतारों को परिभाषित करने के लिए लगता है: people.mozilla.org/~jorendorff/… । मैं एक तरह से या दूसरे इवेंट लूप से संबंधित अनुमान लगाता हूं।
फेलिक्स क्लिंग

@FelixKling लिंक के लिए धन्यवाद - मुझे पता था कि यह कैसे काम किया था, लेकिन अध्याय और कविता उद्धृत नहीं कर सका
Alnitak

2
@FelixKling यह माइक्रोटेक्सेस / मैक्रोटस्क है, यहाँ कल्पना में भाग है कि "डिफर्स" "जब कोई रनिंग एक्ज़ीक्यूशन रेफरेंस नहीं है और एक्ज़ीक्यूटिव रेफरेंस स्टैक खाली है, तो ECMAScript इंप्लीमेंटेशन पहले PendingJob को जॉब क्यू से हटाता है और इसमें मौजूद जानकारी का उपयोग करता है इसमें एक निष्पादन संदर्भ बनाने के लिए और संबंधित जॉब अमूर्त ऑपरेशन का निष्पादन शुरू होता है। "
बेंजामिन ग्रुएनबाम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.