The event loop in nodejs

basic · Node.js — Server-side JavaScript

The Event Loop is the heart of Node.js. It is what allows Node.js to be "non-blocking" and handle thousands of simultaneous connections even though it runs on a single thread . Instead of waiting for a task (like reading a file) to finish, Node.js offloads that task to the system kernel or a thread pool and continues executing other code. When the task is done, the Event Loop picks up the result and executes the associated callback. 1. The Call Stack (The "Right Now" Workspace) Think of the Call Stack as a single-track mind. When your Node.js application starts or receives a request, it runs code line-by-line. Every function that needs to be executed right now gets pushed onto this stack. Because Node.js is single-threaded, only one thing can be on the Call Stack at a time . If a function is currently executing on the stack, everything else must wait. 2. Offloading to the Background When a request comes in that requires a heavy or slow operation—such as reading a file from the disk, fetching data from a database, or making a network API call—Node.js does not let it sit on the Call Stack. If it did, your entire server would freeze while waiting. Instead, the Call Stack instantly offloads that task to the background (either to the computer's underlying operating system kernel or to a background thread pool called libuv). Once the task is handed off, that function is immediately popped off the Call Stack, leaving the stack completely free to handle the next incoming line of code or the next user request. 3. Waiting in the Callback Queue While the main thread is busy executing other things, the background threads are independently processing that slow database or file task. The exact moment that background task finishes, its wrapper function—the Callback containing the result—is sent to wait in a line called the Callback Queue . The callback cannot just jump back onto the Call Stack and interrupt whatever code is currently running; it must wait patiently in this queue. 4. The Event Loop's Single Rule This is where the Event Loop bridges the gap. The Event Loop has one primary, relentless job: it continuously watches both the Call Stack and the Callback Queue . It operates under a strict rule: It will only pull the first callback out of the queue and push it onto the Call Stack if the Call Stack is completely empty. If your synchronous JavaScript code is still running on the stack, the callback sits in the queue. The absolute millisecond the Call Stack finishes its work, clears out, and hits rock bottom, the Event Loop grabs the waiting callback from the queue and pushes it onto the stack, where it is finally executed. How the Event Loop Works When you run a Node.js program, it initializes the event loop, processes the provided input script, and then begins the event loop phases. The 6 Phases of the Event Loop The loop moves through these phases in a specific order. If a phase has no tasks, it moves to the next one. 1. Timers This phase executes callbacks scheduled by setTimeout() and setInterval() . It checks if the "delay" time has passed; if so, it runs the callback. 2. Pending Callbacks This phase executes I/O callbacks that were deferred from the previous loop iteration. Usually, these are callbacks for system errors, like a TCP socket receiving an ECONNREFUSED error. 3. Idle, Prepare This is an internal phase used only by Node.js for house-keeping. Developers don't interact with this. 4. Poll This is the most critical phase. Two things happen here: It calculates how long it should block and poll for I/O. It processes events in the Poll queue . If the queue is empty, the loop will wait here for new I/O events, or move to the next phase if there are setImmediate() scripts waiting. 5. Check This phase is specifically for setImmediate() callbacks. If you want a piece of code to run immediately after the Poll phase finishes, you use setImmediate() . 6. Close Callbacks This phase handles the closing of resources, such as socket.on('close', ...) or httpServer.close() . The "Microtask" Queues (The Interrupters) There are two special queues that are not part of the 6 phases above, but they are executed between phases: process.nextTick() queue Promise callback queue Whenever a phase finishes, Node.js checks these two queues. If there is anything in them, it executes them immediately before moving to the next phase. process.nextTick() has a higher priority than Promises. const fs = require('fs'); setTimeout(() => console.log("1. Timer (setTimeout)"), 0); setImmediate(() => console.log("2. Check (setImmediate)")); fs.readFile(__filename, () => {     console.log("3. Poll (I/O Callback)"); }); process.nextTick(() => console.log("4. Microtask (nextTick)")); Promise.resolve().then(() => console.log("5. Microtask (Promise)")); console.log("6. Synchronous Start"); Predicted Output Order: 6. Synchronous Start (Standard JS execution) 4. Microtask (nextTick) (Highest priority microtask) 5. Microtask (Promise) (Second priority microtask) 1. Timer (setTimeout) (Timer phase) 2. Check (setImmediate) (Check phase) 3. Poll (I/O Callback) (Poll phase - reading the file takes time) Key Takeaways Don't Block the Event Loop: If you run a very heavy mathematical calculation in the main thread, the Event Loop stops. No other requests can be handled until that calculation is done. setImmediate vs setTimeout: setImmediate is designed to execute once the current Poll phase completes. setTimeout schedules a script to run after a minimum threshold in ms has elapsed.

Back to Node.js — Server-side JavaScript

Browse all study material on Careeroza