Kodokon kodokon.com

इवेंट लूप: कॉल स्टैक, माइक्रोटास्क, मैक्रोटास्क

समझें कि इंजन असल में सिंक्रोनस कोड, माइक्रोटास्क और मैक्रोटास्क को कैसे शेड्यूल करता है।

10 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

JavaScript आपका कोड एक सिंगल थ्रेड पर चलाता है, लेकिन इवेंट लूप को ECMAScript परिभाषित नहीं करता: यह HTML स्पेसिफिकेशन है (और Node.js की तरफ libuv) जो बताता है कि यह कैसे काम करता है। इंजन वर्तमान में चल रहे कोड के लिए एक कॉल स्टैक बनाए रखता है, मैक्रोटास्क (टाइमर, I/O, इवेंट) की एक कतार और माइक्रोटास्क (Promise.prototype.then, queueMicrotask, MutationObserver) की एक कतार। स्वर्णिम नियम: प्रत्येक मैक्रोटास्क के बाद, नियंत्रण वापस सौंपे जाने से पहले माइक्रोटास्क कतार को पूरी तरह खाली किया जाता है।

JAVASCRIPT
console.log("script start");

setTimeout(() => console.log("timeout"), 0);

Promise.resolve()
  .then(() => console.log("promise 1"))
  .then(() => console.log("promise 2"));

console.log("script end");
// script start, script end,
// promise 1, promise 2, timeout
माइक्रोटास्क हमेशा मैक्रोटास्क से पहले चलते हैं।

शुरुआती स्क्रिप्ट स्वयं एक मैक्रोटास्क है: जब तक यह समाप्त नहीं होती, कुछ और नहीं चलता। एक बार कॉल स्टैक खाली हो जाने पर, इंजन माइक्रोटास्क कतार को खाली करता है, जिसमें खाली करते समय जोड़े गए माइक्रोटास्क भी शामिल हैं। यह विवरण बताता है कि दो श्रृंखलाबद्ध then कॉल setTimeout(fn, 0) से पहले क्यों चलते हैं: प्रत्येक then एक और माइक्रोटास्क शेड्यूल करता है, और जब तक कतार खाली नहीं हो जाती, नियंत्रण कभी वापस नहीं सौंपा जाता।

JAVASCRIPT
setTimeout(() => console.log("macro 1"), 0);
setTimeout(() => console.log("macro 2"), 0);

queueMicrotask(() => {
  console.log("micro 1");
  queueMicrotask(() => console.log("micro 2"));
});
// micro 1, micro 2, macro 1, macro 2
एक नेस्टेड माइक्रोटास्क किसी भी मैक्रोटास्क से पहले चलता है।

await कीवर्ड इसी तंत्र पर आधारित है: यह async फ़ंक्शन को निलंबित करता है, नियंत्रण को कॉलर को वापस सौंपता है, फिर पुनरारंभ को एक माइक्रोटास्क के रूप में शेड्यूल करता है। यहाँ तक कि await null भी यह निलंबन ट्रिगर करता है, क्योंकि मान को पहले से हल किए गए प्रॉमिस में लपेट दिया जाता है। इसीलिए await के बाद रखा गया कोड कभी सिंक्रोनस रूप से नहीं चलता।

JAVASCRIPT
async function main() {
  console.log("before await");
  await null;
  console.log("after await");
}

main();
console.log("sync code");
// before await, sync code, after await
await फ़ंक्शन को निलंबित करता है और बाकी हिस्से को पुनः शेड्यूल करता है।

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. एक स्क्रिप्ट सिंक्रोनस रूप से C लॉग करती है, setTimeout(fn, 0) के माध्यम से A और Promise.resolve().then के माध्यम से B शेड्यूल करती है। अक्षर किस क्रम में दिखाई देते हैं?
    • A, B, C
    • C, A, B
    • C, B, A
    • B, C, A
  2. माइक्रोटास्क कतार कब खाली की जाती है?
    • प्रत्येक मैक्रोटास्क के बाद, पूरी तरह से, खाली करते समय जोड़े गए माइक्रोटास्क सहित
    • दो मैक्रोटास्क के बीच केवल एक माइक्रोटास्क चलता है
    • हर 16 ms में, पेज रेंडर होने से ठीक पहले
    • केवल तब जब सभी मैक्रोटास्क संसाधित हो चुके हों
  3. await अंदर से असल में क्या करता है?
    • यह प्रॉमिस के हल होने तक थ्रेड को ब्लॉक करता है
    • यह async फ़ंक्शन को निलंबित करता है और उसके पुनरारंभ को एक माइक्रोटास्क के रूप में शेड्यूल करता है
    • यह फ़ंक्शन के बाकी हिस्से को एक मैक्रोटास्क में बदल देता है
    • यदि प्रतीक्षित मान प्रॉमिस नहीं है तो यह कुछ नहीं करता