किसी फ़ंक्शन के अंदर इसे संशोधित करने के बाद मेरा वेरिएबल अनलग्ड क्यों है? - एसिंक्रोनस कोड संदर्भ


736

निम्नलिखित उदाहरणों को देखते हुए, outerScopeVarसभी मामलों में अपरिभाषित क्यों है ?

var outerScopeVar;

var img = document.createElement('img');
img.onload = function() {
    outerScopeVar = this.width;
};
img.src = 'lolcat.png';
alert(outerScopeVar);

var outerScopeVar;
setTimeout(function() {
    outerScopeVar = 'Hello Asynchronous World!';
}, 0);
alert(outerScopeVar);

// Example using some jQuery
var outerScopeVar;
$.post('loldog', function(response) {
    outerScopeVar = response;
});
alert(outerScopeVar);

// Node.js example
var outerScopeVar;
fs.readFile('./catdog.html', function(err, data) {
    outerScopeVar = data;
});
console.log(outerScopeVar);

// with promises
var outerScopeVar;
myPromise.then(function (response) {
    outerScopeVar = response;
});
console.log(outerScopeVar);

// geolocation API
var outerScopeVar;
navigator.geolocation.getCurrentPosition(function (pos) {
    outerScopeVar = pos;
});
console.log(outerScopeVar);

undefinedइन सभी उदाहरणों में इसका उत्पादन क्यों होता है ? मुझे वर्कअराउंड नहीं चाहिए, मैं जानना चाहता हूं कि ऐसा क्यों हो रहा है।


नोट: यह जावास्क्रिप्ट अतुल्यकालिकता के लिए एक विहित प्रश्न है । इस प्रश्न को सुधारने और अधिक सरलीकृत उदाहरण जोड़ने के लिए स्वतंत्र महसूस करें, जिसे समुदाय पहचान सकता है।



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

5
थोड़ा और सोचा जाना, "कैनोनिकल एसिंक्रोनसिटी विषय" शीर्षक पर थोड़ा भारी है, "अतुल्यकालिक कोड संदर्भ" सरल और अधिक उद्देश्य है। मेरा मानना ​​है कि ज्यादातर लोग "एसिंक्रोनस" के बजाय "एसिंक्रोनस" की खोज करते हैं।
फेबेरिसो मैटे

2
कुछ लोग फ़ंक्शन कॉल से पहले अपने चर को इनिशियलाइज़ करते हैं। कैसे शीर्षक बदलने के बारे में जो किसी भी तरह का प्रतिनिधित्व करता है? जैसे " किसी फ़ंक्शन के अंदर इसे संशोधित करने के बाद मेरा वेरिएबल अनलग्ड क्यों है ?" ?
फेलिक्स क्लिंग

सभी कोड उदाहरणों में जो आपने ऊपर उल्लेख किया है, "चेतावनी (आउटरस्कोपवर);" अभी क्रियान्वित होता है, जबकि "आउटरस्कोपवार" के मान को निर्दिष्ट करते हुए लेटर (एसिंक्रोनसली) होता है।
रिफ्लेक्टर

जवाबों:


580

एक शब्द का जवाब: अतुल्यकालिकता

भूमिकाएँ

इस विषय को, स्टैक ओवरफ्लो में, कम से कम हज़ारों बार देखा गया है। इसलिए, सबसे पहले मैं कुछ अत्यंत उपयोगी संसाधनों को इंगित करना चाहूंगा:


सवाल का जवाब हाथ में

आइए पहले सामान्य व्यवहार का पता लगाएं। सभी उदाहरणों में, outerScopeVarएक फ़ंक्शन के अंदर संशोधित किया गया है । उस फ़ंक्शन को स्पष्ट रूप से तुरंत निष्पादित नहीं किया जाता है, इसे एक तर्क के रूप में सौंपा या पारित किया जा रहा है। जिसे हम कॉलबैक कहते हैं ।

अब सवाल यह है कि उस कॉलबैक को कब कहा जाता है?

यह केस पर निर्भर करता है। आइए फिर से कुछ सामान्य व्यवहार का पता लगाने की कोशिश करें:

  • img.onloadभविष्य में किसी समय कहा जा सकता है , जब (और यदि) छवि सफलतापूर्वक लोड हो गई है।
  • setTimeoutविलंब समाप्त होने के बाद और समय समाप्त होने के बाद रद्द नहीं किया गया है, भविष्य में कुछ समय के लिए कहा जा सकता है clearTimeout। नोट: 0विलंब के रूप में उपयोग करने पर भी , सभी ब्राउज़रों में न्यूनतम टाइमआउट विलंब कैप (HTML5 युक्ति में 4ms तक निर्दिष्ट) है।
  • jQuery $.postके कॉलबैक को भविष्य में , (और यदि) Ajax के अनुरोध को सफलतापूर्वक पूरा किया जा सकता है।
  • Node.js को भविष्य में कभीfs.readFile भी कॉल किया जा सकता है , जब फ़ाइल को सफलतापूर्वक पढ़ा गया है या त्रुटि डाली गई है।

सभी मामलों में, हमारे पास एक कॉलबैक है जो भविष्य में कभी भी चल सकता है । यह "भविष्य में कुछ समय" है जिसे हम अतुल्यकालिक प्रवाह के रूप में संदर्भित करते हैं

अतुल्यकालिक निष्पादन को तुल्यकालिक प्रवाह से बाहर धकेल दिया जाता है। अर्थात, एसिंक्रोनस कोड कभी निष्पादित नहीं करेगा जबकि सिंक्रोनस कोड स्टैक निष्पादित हो रहा है। यह जावास्क्रिप्ट के एकल-पिरोया जाने का अर्थ है।

अधिक विशेष रूप से, जब जेएस इंजन निष्क्रिय होता है - (क) सिंक्रोनस कोड के स्टैक को निष्पादित नहीं करना - यह उन घटनाओं के लिए मतदान करेगा, जो अतुल्यकालिक कॉलबैक (जैसे कि समय समाप्त हो गया, नेटवर्क प्रतिक्रिया) को ट्रिगर कर सकते हैं और उन्हें एक के बाद एक निष्पादित कर सकते हैं। इसे इवेंट लूप माना जाता है ।

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

async कोड हाइलाइट किया गया

संक्षेप में, कॉलबैक फ़ंक्शंस को सिंक्रोनाइज़ किया जाता है लेकिन एसिंक्रोनस रूप से निष्पादित किया जाता है। आप बस एक अतुल्यकालिक फ़ंक्शन के निष्पादन पर भरोसा नहीं कर सकते हैं जब तक कि आप यह नहीं जानते कि यह निष्पादित हो गया है, और यह कैसे करना है?

यह वास्तव में सरल है। तर्क जो अतुल्यकालिक फ़ंक्शन निष्पादन पर निर्भर करता है, उसे इस अतुल्यकालिक फ़ंक्शन के अंदर से शुरू / बुलाया जाना चाहिए। उदाहरण के लिए, कॉलबैक फ़ंक्शन के अंदर भी alerts और console.logs को ले जाना अपेक्षित परिणाम का उत्पादन करेगा, क्योंकि परिणाम उस बिंदु पर उपलब्ध है।

अपने स्वयं के कॉलबैक तर्क को लागू करना

अक्सर आपको एक अतुल्यकालिक फ़ंक्शन के परिणाम के साथ अधिक चीजें करने की आवश्यकता होती है या परिणाम के साथ अलग-अलग चीजें करते हैं, जिसके आधार पर अतुल्यकालिक फ़ंक्शन को कहा जाता है। चलिए थोड़ा और जटिल उदाहरण पेश करते हैं:

var outerScopeVar;
helloCatAsync();
alert(outerScopeVar);

function helloCatAsync() {
    setTimeout(function() {
        outerScopeVar = 'Nya';
    }, Math.random() * 2000);
}

नोट: मैं setTimeoutजेनेरिक एसिंक्रोनस फ़ंक्शन के रूप में एक यादृच्छिक देरी के साथ उपयोग कर रहा हूं , वही उदाहरण अजाक्स readFile, onloadऔर किसी अन्य एसिंक्रोनस प्रवाह पर लागू होता है ।

यह उदाहरण स्पष्ट रूप से अन्य उदाहरणों के समान मुद्दे से ग्रस्त है, यह तब तक इंतजार नहीं कर रहा है जब तक अतुल्यकालिक फ़ंक्शन निष्पादित नहीं होता है।

आइए इससे निपटने के लिए अपने स्वयं के कॉलबैक सिस्टम को लागू करें। सबसे पहले, हम उस बदसूरत से छुटकारा पा लेते हैं outerScopeVarजो इस मामले में पूरी तरह से बेकार है। फिर हम एक पैरामीटर जोड़ते हैं जो एक फ़ंक्शन तर्क, हमारे कॉलबैक को स्वीकार करता है। जब एसिंक्रोनस ऑपरेशन खत्म हो जाता है, तो हम इस कॉलबैक को परिणाम पास करते हैं। कार्यान्वयन (कृपया टिप्पणियों को क्रम में पढ़ें):

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}

उपरोक्त उदाहरण का कोड स्निपेट:

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
console.log("1. function called...")
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    console.log("5. result is: ", result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    console.log("2. callback here is the function passed as argument above...")
    // 3. Start async operation:
    setTimeout(function() {
    console.log("3. start async operation...")
    console.log("4. finished async operation, calling the callback, passing the result...")
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}

ज्यादातर वास्तविक उपयोग के मामलों में, DOM API और अधिकांश लाइब्रेरी पहले से ही कॉलबैक कार्यक्षमता ( helloCatAsyncइस प्रदर्शनकारी उदाहरण में कार्यान्वयन) प्रदान करते हैं। आपको केवल कॉलबैक फ़ंक्शन को पास करने और यह समझने की आवश्यकता है कि यह तुल्यकालिक प्रवाह से बाहर निकलेगा, और इसके लिए आपके कोड को फिर से व्यवस्थित करेगा।

आप यह भी देखेंगे कि अतुल्यकालिक प्रकृति के कारण, returnअतुल्यकालिक प्रवाह से वापस तुल्यकालिक प्रवाह तक एक मूल्य के लिए असंभव है जहां कॉलबैक को परिभाषित किया गया था, क्योंकि अतुल्यकालिक कॉलबैक को तब निष्पादित किया जाता है जब सिंक्रोनस कोड पहले ही निष्पादित करना समाप्त कर देता है।

returnएक अतुल्यकालिक कॉलबैक से आईएनजी के बजाय , आपको कॉलबैक पैटर्न का उपयोग करना होगा, या ... वादे।

वादे

यद्यपि वेनिला जेएस के साथ कॉलबैक नरक को बनाए रखने के तरीके हैं , वादे लोकप्रियता में बढ़ रहे हैं और वर्तमान में ES6 में मानकीकृत किए जा रहे हैं (देखें वादा - एमडीएन )।

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


जावास्क्रिप्ट अतुल्यकालिकता के बारे में अधिक पढ़ने की सामग्री

  • नोड की कला - कॉलबैक एसिंक्रोनस कोड और कॉलबैक को वैनिला जेएस उदाहरणों और नोड कोड के साथ बहुत अच्छी तरह से समझाता है।

नोट: मैंने इस उत्तर को समुदाय विकी के रूप में चिह्नित किया है, इसलिए कम से कम 100 प्रतिष्ठा वाले कोई भी इसे संपादित और सुधार सकता है! कृपया इस उत्तर को बेहतर बनाने के लिए स्वतंत्र महसूस करें, या यदि आप चाहें तो एक नया उत्तर प्रस्तुत करें।

मैं इस प्रश्न को एक अतुल्यकालिक मुद्दों का जवाब देने के लिए एक विहित विषय में बदलना चाहता हूं जो अजाक्स से असंबंधित है ( एक AJAX कॉल से प्रतिक्रिया कैसे लौटाएं? इसके लिए), इसलिए इस विषय को आपकी मदद करने के लिए जितना संभव हो उतना अच्छा और उपयोगी होना चाहिए? !


1
आपके अंतिम उदाहरण में, क्या कोई विशिष्ट कारण है कि आप अनाम फ़ंक्शंस का उपयोग करते हैं या नामांकित फ़ंक्शंस का उपयोग करके समान काम करेंगे?
JDelage

1
कोड उदाहरण थोड़ा अजीब हैं क्योंकि आप इसे कॉल करने के बाद फ़ंक्शन की घोषणा कर रहे हैं। पाठ्यक्रम के उत्थापन के कारण काम करता है, लेकिन क्या यह जानबूझकर किया गया था?
बरगी

2
क्या यह गतिरोध है felix kling आपके उत्तर की ओर इशारा कर रहा है और आप felix उत्तर की ओर इशारा कर रहे हैं
माही

1
आपको यह समझने की आवश्यकता है कि लाल वृत्त कोड केवल async है क्योंकि इसे NATIVE async जावास्क्रिप्ट फ़ंक्शंस द्वारा निष्पादित किया जा रहा है। यह आपके जावास्क्रिप्ट इंजन की एक विशेषता है - चाहे वह Node.js हो या एक ब्राउज़र। यह async है क्योंकि यह एक फ़ंक्शन के लिए "कॉलबैक" के रूप में पारित किया जा रहा है जो अनिवार्य रूप से एक ब्लैक बॉक्स है (C आदि में लागू किया गया है)। असहाय डेवलपर के लिए वे async हैं ... सिर्फ इसलिए। यदि आप अपना स्वयं का एसिंक्स फ़ंक्शन लिखना चाहते हैं, तो आपको इसे सेटटाइमआउट (myfunc, 0) में भेजकर इसे हैक करना होगा। क्या आपको ऐसा करना चाहिए? एक और बहस .... शायद नहीं।
सीन एंडरसन

@Fabricio मैं कल्पना "> = 4ms क्लैंप" को परिभाषित करने के लिए देखा है, लेकिन यह नहीं मिल सकता है - मैं MDN (नेस्टेड कॉल क्लैम्पिंग के लिए) ही एक तंत्र के कुछ उल्लेख पाया - developer.mozilla.org/en-US/docs / वेब / एपीआई /… - क्या किसी के पास एचटीएमएल कल्पना के दाहिने हिस्से का लिंक है।
सेबी

156

Fabrício का जवाब हाजिर है; लेकिन मैं कुछ कम तकनीकी के साथ उनके जवाब को पूरक करना चाहता था, जो कि एसिंक्रोनसिटी की अवधारणा को समझाने में मदद करने के लिए एक समानता पर ध्यान केंद्रित करता है


एक सादृश्य ...

कल, मैं जो काम कर रहा था वह एक सहयोगी से कुछ जानकारी के लिए आवश्यक था। मैंने उसे ऊपर उठाया; यहाँ बातचीत कैसे हुई:

मेरे : हाय बॉब, मुझे पता है कि कैसे हम जरूरत foo 'घ बार ' पिछले सप्ताह d। जिम इस पर एक रिपोर्ट चाहते हैं, और आप केवल एक ही हैं जो इसके बारे में विवरण जानते हैं।

बॉब : ज़रूर बात है, लेकिन मुझे लगभग 30 मिनट लगेंगे?

मैं : यह बहुत अच्छा है बॉब। जब आपको जानकारी मिली हो तो मुझे एक अंगूठी वापस दें!

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


कल्पना करें कि क्या बातचीत इसके बजाय इस तरह से चली गई थी;

मेरे : हाय बॉब, मुझे पता है कि कैसे हम जरूरत foo 'घ बार ' पिछले सप्ताह d। जिम इस पर एक रिपोर्ट चाहते हैं, और आप केवल एक ही हैं जो इसके बारे में विवरण जानते हैं।

बॉब : ज़रूर बात है, लेकिन मुझे लगभग 30 मिनट लगेंगे?

मैं : यह बहुत अच्छा है बॉब। मैं इंतजार करूँगा।

और मैं वहीं बैठ कर इंतजार करने लगा। और इंतजार किया। और इंतजार किया। 40 मिनट के लिए। इंतजार के सिवा कुछ नहीं। आखिरकार, बॉब ने मुझे जानकारी दी, हमने हंगामा किया और मैंने अपनी रिपोर्ट पूरी की। लेकिन मैं उत्पादकता के 40 मिनट खो दिया है।


यह एसिंक्रोनस बनाम तुल्यकालिक व्यवहार है

यह वही है जो हमारे प्रश्न में सभी उदाहरणों में हो रहा है। एक छवि लोड हो रहा है, डिस्क से एक फ़ाइल लोड हो रहा है, और AJAX के माध्यम से एक पृष्ठ का अनुरोध सभी धीमी गति से संचालन कर रहे हैं (आधुनिक कंप्यूटिंग के संदर्भ में)।

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

var outerScopeVar;    
var img = document.createElement('img');

// Here we register the callback function.
img.onload = function() {
    // Code within this function will be executed once the image has loaded.
    outerScopeVar = this.width;
};

// But, while the image is loading, JavaScript continues executing, and
// processes the following lines of JavaScript.
img.src = 'lolcat.png';
alert(outerScopeVar);

उपरोक्त कोड में, हम जावास्क्रिप्ट को लोड करने के लिए कह रहे हैं lolcat.png, जो एक स्लो ऑपरेशन है। इस धीमे संचालन के बाद कॉलबैक फ़ंक्शन निष्पादित किया जाएगा, लेकिन इस बीच, जावास्क्रिप्ट कोड की अगली पंक्तियों को संसाधित करता रहेगा; यानी alert(outerScopeVar)

यही कारण है कि हम सतर्क दिखाते हैं undefined; चूंकि alert()छवि को लोड किए जाने के बजाय तुरंत संसाधित किया जाता है।

अपने कोड को ठीक करने के लिए, हमें केवल कॉलबैक फ़ंक्शन मेंalert(outerScopeVar) कोड को स्थानांतरित करना होगा । इसके परिणामस्वरूप, हमें अब outerScopeVarवैरिएबल के रूप में घोषित किए गए वैरिएबल की आवश्यकता नहीं है ।

var img = document.createElement('img');

img.onload = function() {
    var localScopeVar = this.width;
    alert(localScopeVar);
};

img.src = 'lolcat.png';

आप हमेशा देखेंगे कि एक कॉलबैक एक फ़ंक्शन के रूप में निर्दिष्ट है, क्योंकि कुछ कोड को परिभाषित करने के लिए जावास्क्रिप्ट में एकमात्र * तरीका है, लेकिन बाद तक इसे निष्पादित नहीं करें।

इसलिए, हमारे सभी उदाहरणों में, function() { /* Do something */ }कॉलबैक है; सभी उदाहरणों को ठीक करने के लिए, हमें केवल उस कोड को स्थानांतरित करना होगा जिसमें ऑपरेशन की प्रतिक्रिया की आवश्यकता है!

* तकनीकी रूप से आप इसका उपयोग कर सकते हैं eval(), लेकिन इस उद्देश्य के लिए eval()बुराई है


मैं अपने कॉलर को प्रतीक्षा में कैसे रखूं?

वर्तमान में आपके पास इसके समान कुछ कोड हो सकते हैं;

function getWidthOfImage(src) {
    var outerScopeVar;

    var img = document.createElement('img');
    img.onload = function() {
        outerScopeVar = this.width;
    };
    img.src = src;
    return outerScopeVar;
}

var width = getWidthOfImage('lolcat.png');
alert(width);

हालांकि, अब हम जानते हैं कि return outerScopeVarतुरंत होता है; onloadकॉलबैक फ़ंक्शन से पहले चर को अद्यतन किया गया है। यह getWidthOfImage()वापस लौटने undefinedऔर undefinedसतर्क रहने की ओर जाता है ।

इसे ठीक करने के लिए, हमें getWidthOfImage()कॉलबैक को पंजीकृत करने के लिए फ़ंक्शन को कॉल करने की अनुमति देने की आवश्यकता है , फिर उस कॉलबैक के भीतर होने वाली चौड़ाई के एलर्टिंग को स्थानांतरित करें;

function getWidthOfImage(src, cb) {     
    var img = document.createElement('img');
    img.onload = function() {
        cb(this.width);
    };
    img.src = src;
}

getWidthOfImage('lolcat.png', function (width) {
    alert(width);
});

... पहले की तरह, ध्यान दें कि हम वैश्विक चर (इस मामले में width) निकालने में सक्षम हैं ।


4
लेकिन यदि आप किसी भिन्न गणना में परिणामों का उपयोग करना चाहते हैं या किसी वस्तु चर में संग्रहीत करना चाहते हैं, तो यह कैसे उपयोगी है, इसके लिए आपको क्या करना है?
केन इंग्राम

73

यहां उन लोगों के लिए अधिक संक्षिप्त जवाब दिया गया है जो त्वरित संदर्भ के साथ-साथ कुछ उदाहरणों का उपयोग कर रहे हैं जो वादे और async / प्रतीक्षा का उपयोग कर रहे हैं।

उस फ़ंक्शन के लिए भोले दृष्टिकोण (जो काम नहीं करता है) के साथ शुरू करें जो एक अतुल्यकालिक विधि (इस मामले में setTimeout) को कॉल करता है और एक संदेश देता है:

function getMessage() {
  var outerScopeVar;
  setTimeout(function() {
    outerScopeVar = 'Hello asynchronous world!';
  }, 0);
  return outerScopeVar;
}
console.log(getMessage());

undefinedइस मामले में लॉग इन किया जाता है क्योंकि कॉलबैक कॉल करने और अपडेट getMessageहोने से पहले रिटर्न ।setTimeoutouterScopeVar

इसे हल करने के दो मुख्य तरीके कॉलबैक और वादों का उपयोग कर रहे हैं :

कॉलबैक

यहां परिवर्तन यह है कि getMessageएक callbackपैरामीटर को स्वीकार करता है जिसे कॉलिंग कोड पर परिणाम उपलब्ध कराने के लिए एक बार उपलब्ध कराया जाएगा।

function getMessage(callback) {
  setTimeout(function() {
    callback('Hello asynchronous world!');
  }, 0);
}
getMessage(function(message) {
  console.log(message);
});

वादे

वादे एक विकल्प प्रदान करते हैं जो कॉलबैक की तुलना में अधिक लचीला होता है क्योंकि उन्हें स्वाभाविक रूप से कई async संचालन समन्वय करने के लिए जोड़ा जा सकता है। एक वादा / ए + मानक कार्यान्वयन मूल रूप से नोड.जेएस (0.12+) और कई वर्तमान ब्राउज़रों में प्रदान किया जाता है, लेकिन ब्लूबर्ड और क्यू जैसी पुस्तकालयों में भी लागू किया जाता है ।

function getMessage() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve('Hello asynchronous world!');
    }, 0);
  });
}

getMessage().then(function(message) {
  console.log(message);  
});

jQuery के आस्थगित

jQuery कार्यक्षमता प्रदान करता है जो अपने Deferreds के साथ वादों के समान है।

function getMessage() {
  var deferred = $.Deferred();
  setTimeout(function() {
    deferred.resolve('Hello asynchronous world!');
  }, 0);
  return deferred.promise();
}

getMessage().done(function(message) {
  console.log(message);  
});

async / इंतजार

यदि आपके जावास्क्रिप्ट वातावरण में ( asyncऔर awaitNode.js 7.6+ की तरह) समर्थन शामिल है , तो आप फ़ंक्शनल रूप से फ़ंक्शंस का उपयोग कर सकते हैं async:

function getMessage () {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve('Hello asynchronous world!');
        }, 0);
    });
}

async function main() {
    let message = await getMessage();
    console.log(message);
}

main();

पिछले कुछ घंटों से प्रोमिस पर आपका नमूना मूल रूप से वही है जो मैं खोज रहा था। आपका उदाहरण सुंदर है और एक ही समय में वादे बताते हैं। यह कहीं और क्यों नहीं है।
विंसेंट पी

यह सब ठीक है, लेकिन क्या होगा अगर आपको मापदंडों के साथ गेटमेसेज () कॉल करने की आवश्यकता है? उस परिदृश्य में आप ऊपर कैसे लिखेंगे?
चिवड़ा

2
@Chiwda तुम बस कॉलबैक पैरामीटर पिछले रखा function getMessage(param1, param2, callback) {...}:।
जॉनीएचके

मैं आपके async/awaitनमूने की कोशिश कर रहा हूं , लेकिन मैं समस्याओं में भाग रहा हूं। एक पल को रोकने के बजाय new Promise, मैं एक .Get()कॉल कर रहा हूं और इसलिए किसी भी resolve()तरीके की पहुंच नहीं है । इस प्रकार मेरा getMessage()वादा लौट रहा है और परिणाम नहीं। क्या आप इसके लिए अपना वाक्य संपादित कर सकते हैं कि इसके लिए एक सिंटैक्स दिखा सकें?
InteXX

@InteXX मुझे यकीन नहीं है कि आप .Get()कॉल करने के बारे में क्या मतलब रखते हैं । शायद एक नया प्रश्न पोस्ट करने के लिए सबसे अच्छा है।
जॉनीएचके

56

स्पष्ट बताने के लिए, कप का प्रतिनिधित्व करता है outerScopeVar

अतुल्यकालिक कार्यों की तरह ...

कॉफी के लिए अतुल्यकालिक कॉल


14
जबकि एक अतुल्यकालिक कार्य अधिनियम को समकालिक बनाने की कोशिश करते हुए 1 सेकंड में कॉफी पीने की कोशिश की जाएगी, और इसे 1 मिनट में आपकी गोद में डाल दिया जाएगा।
तेयपेमम

यदि यह स्पष्ट था, तो मुझे नहीं लगता कि सवाल पूछा जाएगा, नहीं?
ब्रोकोली

2
@ ब्रोकली
२०००

14

अन्य उत्तर बहुत अच्छे हैं और मैं सिर्फ इस बारे में एक सीधा जवाब देना चाहता हूं। बस jQuery अतुल्यकालिक कॉल करने के लिए सीमित है

सभी ajax कॉल (सहित $.getया $.postया $.ajax) अतुल्यकालिक कर रहे हैं।

अपने उदाहरण को देखते हुए

var outerScopeVar;  //line 1
$.post('loldog', function(response) {  //line 2
    outerScopeVar = response;
});
alert(outerScopeVar);  //line 3

कोड निष्पादन लाइन 1 से शुरू होता है, जो चर और ट्रिगर को घोषित करता है और लाइन 2 पर अतुल्यकालिक कॉल करता है, (यानी, पोस्ट अनुरोध) और यह लाइन 3 से अपने निष्पादन को जारी रखता है, बिना पोस्ट के इंतजार के इसके निष्पादन को पूरा करने के लिए।

कहते हैं कि पोस्ट अनुरोध को पूरा होने में 10 सेकंड लगते हैं, outerScopeVarइच्छा का मूल्य केवल उन 10 सेकंड के बाद सेट किया जाएगा।

कठिन परीक्षा लेना,

var outerScopeVar; //line 1
$.post('loldog', function(response) {  //line 2, takes 10 seconds to complete
    outerScopeVar = response;
});
alert("Lets wait for some time here! Waiting is fun");  //line 3
alert(outerScopeVar);  //line 4

अब जब आप इसे निष्पादित करते हैं, तो आपको पंक्ति 3 पर एक अलर्ट मिलेगा। अब कुछ समय तक प्रतीक्षा करें जब तक कि आप सुनिश्चित न हों कि पोस्ट अनुरोध ने कुछ मूल्य वापस कर दिया है। फिर जब आप अलर्ट बॉक्स पर ओके पर क्लिक करते हैं, तो अगला अलर्ट अपेक्षित मूल्य प्रिंट करेगा, क्योंकि आपने इसके लिए इंतजार किया था।

वास्तविक जीवन परिदृश्य में, कोड बन जाता है,

var outerScopeVar;
$.post('loldog', function(response) {
    outerScopeVar = response;
    alert(outerScopeVar);
});

सभी कोड जो अतुल्यकालिक कॉल पर निर्भर करते हैं, को अतुल्यकालिक ब्लॉक के अंदर स्थानांतरित किया जाता है, या अतुल्यकालिक कॉल पर प्रतीक्षा करके।


or by waiting on the asynchronous callsकिसी से ऐसा कैसे संभव है?
InteXX

@InteXX कॉलबैक विधि का उपयोग करके
तेजा

क्या आपके पास एक त्वरित वाक्यविन्यास उदाहरण है?
इंटेक्सएक्सएक्सएक्स

11

इन सभी स्थितियों में outerScopeVarसंशोधित या एक मूल्य असाइन किया गया है एसिंक्रोनस रूप से या बाद में किसी समय में हो रहा (इंतजार कर या किसी घटना होने के लिए सुन रहा), जिसके लिए वर्तमान निष्पादन के लिए इंतजार नहीं होगा तो इन सभी मामलों वर्तमान निष्पादन प्रवाह परिणामों मेंouterScopeVar = undefined

आइए प्रत्येक उदाहरणों पर चर्चा करें (मैंने उस हिस्से को चिह्नित किया है जिसे असिंक्रोनसली कहा जाता है या कुछ घटनाओं के होने में देरी होती है):

1।

यहां छवि विवरण दर्ज करें

यहां हम एक घटना सूची को पंजीकृत करते हैं, जिसे उस विशेष घटना पर निष्पादित किया जाएगा। छवि का लोड हो रहा है। फिर अगली लाइनों के साथ वर्तमान निष्पादन निरंतर होता है img.src = 'lolcat.png';और alert(outerScopeVar);इस बीच घटना नहीं हो सकती है। यानी, फंतासी img.onloadको लोड करने के लिए , अतुलनीय रूप से संदर्भित छवि के लिए प्रतीक्षा करें। यह सभी फ़ोलोइंग उदाहरण होगा- घटना भिन्न हो सकती है।

2।

2

यहां टाइमआउट इवेंट भूमिका निभाता है, जो निर्दिष्ट समय के बाद हैंडलर को आमंत्रित करेगा। यहाँ यह है 0, लेकिन फिर भी यह एक अतुल्यकालिक घटना को पंजीकृत करता है इसे Event Queueनिष्पादन की अंतिम स्थिति में जोड़ा जाएगा , जो कि गारंटी में देरी करता है।

3।

यहां छवि विवरण दर्ज करें इस बार अजाक्स कॉलबैक।

4।

यहां छवि विवरण दर्ज करें

नोड को अतुल्यकालिक कोडिंग के राजा के रूप में माना जा सकता है। चिह्नित फ़ंक्शन को कॉलबैक हैंडलर के रूप में पंजीकृत किया जाता है जिसे निर्दिष्ट फ़ाइल पढ़ने के बाद निष्पादित किया जाएगा।

5।

यहां छवि विवरण दर्ज करें

स्पष्ट वादा (भविष्य में कुछ किया जाएगा) अतुल्यकालिक है। देखें कि जावास्क्रिप्ट में Deferred, Promise और Future के बीच क्या अंतर हैं?

https://www.quora.com/Whats-the-difference-between-a-promise-and-a-callback-in-Javascript

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