NodeJS Event Loop

दोस्तों, जब भी हम backend development की बात करते हैं, तो NodeJS का नाम सबसे पहले आता है। NodeJS अपनी बेहतरीन speed और performance के लिए जाना जाता है। लेकिन क्या आपने कभी सोचा है कि NodeJS single-threaded होने के बावजूद हज़ारों requests को एक साथ कैसे handle कर लेता है?

इसका असली राज़ छुपा है NodeJS के दिल यानी Event Loop में। अगर आप NodeJS developer बनना चाहते हैं या full-stack interview की तैयारी कर रहे हैं, तो Event Loop का concept समझना आपके लिए बेहद ज़रूरी है। आज के इस tutorial में हम बिल्कुल आसान शब्दों में NodeJS Event Loop की पूरी वर्किंग को समझेंगे।

Single-Threaded Non-Blocking I/O क्या है?

पारंपरिक backend technologies (जैसे PHP या older Java structures) multi-threaded होती हैं। यानी हर new request के लिए एक नया thread बनता है। लेकिन NodeJS Single-Threaded है, इसका मतलब इसके पास काम करने के लिए सिर्फ एक ही main thread (v8 engine code executor) होता है।

अब सवाल उठता है: अगर एक thread किसी heavy database query या file reading में व्यस्त हो गया, तो क्या पूरा server block हो जाएगा?

जवाब है: नहीं! NodeJS Non-blocking I/O का उपयोग करता है। जब भी कोई heavy operation आता है, NodeJS उसे background में भेज देता है और main thread अगली request को handle करने के लिए free हो जाता है। जब background task पूरा हो जाता है, तो callback function को execute करने के लिए Event Loop उसे main call stack में वापस लाता है।

Event Loop के Phases (चरण)

Event Loop एक loop की तरह लगातार चलता रहता है और इसके मुख्य 6 phases होते हैं:

  1. Timers Phase: यहाँ setTimeout() और setInterval() के callbacks execute होते हैं।
  2. Pending Callbacks: पिछले loop cycle के बचे हुए I/O callbacks यहाँ execute होते हैं।
  3. Idle, Prepare: यह phase सिर्फ NodeJS internals के लिए उपयोग होता है।
  4. Poll Phase: नए incoming connection और I/O (files, network requests) callbacks यहाँ handle होते हैं।
  5. Check Phase: यहाँ setImmediate() के callbacks execute होते हैं।
  6. Close Callbacks: जैसे socket.on('close') callbacks यहाँ execute होते हैं।

Execution Order Testing (Live Code Example)

चलिए एक बेहतरीन code example से समझते हैं कि कौन सा function पहले run होगा। आप इस code को अपने local machine पर run करके देख सकते हैं:

const fs = require('fs');

console.log("1. Script Start");

// 1. setTimeout (Timer Phase)
setTimeout(() => {
  console.log("2. setTimeout (Timer Phase) - 0ms");
}, 0);

// 2. setImmediate (Check Phase)
setImmediate(() => {
  console.log("3. setImmediate (Check Phase)");
});

// 3. File Read (Poll Phase I/O)
fs.readFile(__filename, () => {
  console.log("4. File Reading Complete (Poll Phase)");
  
  // Microtasks inside I/O callback
  setTimeout(() => {
    console.log("5. Nested setTimeout inside File Read");
  }, 0);
  
  setImmediate(() => {
    console.log("6. Nested setImmediate inside File Read");
  });
  
  process.nextTick(() => {
    console.log("7. process.nextTick inside File Read");
  });
});

// 4. process.nextTick (Microtask Queue - Priority #1)
process.nextTick(() => {
  console.log("8. process.nextTick (High Priority Microtask)");
});

console.log("9. Script End");

Output Explanation (Execution Order):

जब आप ऊपर दिए गए code को run करेंगे, तो output का क्रम कुछ ऐसा होगा:

  • सबसे पहले synchronous code run होगा: 1. Script Start, 9. Script End.
  • फिर High Priority Microtask run होगा: 8. process.nextTick.
  • फिर Event loop start होगा: 2. setTimeout - 0ms run होगा.
  • फिर check phase में 3. setImmediate run होगा.
  • इसके बाद background operation complete होने पर read callback run होगा: 4. File Reading Complete.
  • I/O callback के अंदर 7. process.nextTick पहले run होगा, फिर check phase में 6. Nested setImmediate run होगा, और अंत में timers phase में 5. Nested setTimeout run होगा.

Dhyan Dene Wali Baat (Common Mistake)

हमेशा याद रखें कि process.nextTick() Event Loop का हिस्सा नहीं है, बल्कि यह microtask queue का हिस्सा है जो हर phase के तुरंत बाद run होता है। यदि आप process.nextTick() के अंदर एक loop चला देंगे, तो Event Loop block हो जाएगा और आपका server crash हो सकता है!

Frequently Asked Questions (FAQs)

Q1: NodeJS single-threaded है तो multi-threading कैसे करता है?

NodeJS v8 engine JavaScript single-threaded run करता है, लेकिन file operations और cryptography जैसे tasks के लिए NodeJS C++ backend library libuv के **Thread Pool** (default 4 threads) का उपयोग करता है जो asynchronous background operations handle करते हैं।

Q2: setTimeout(fn, 0) और setImmediate(fn) में क्या अंतर है?

Normal script flow में इन दोनों का order unpredictable (unstable) होता है, लेकिन किसी asynchronous I/O callback के अंदर run करने पर setImmediate हमेशा setTimeout से पहले run होता है क्योंकि I/O के बाद check phase पहले आता है।

Q3: CPU intensive tasks के लिए NodeJS अच्छा क्यों नहीं है?

CPU intensive tasks (जैसे video processing, heavy calculations) main thread को block कर देते हैं, जिससे बाकी requests wait state में चली जाती हैं। ऐसे कामों के लिए Worker Threads का उपयोग किया जाता है।