Understanding the Node.js Event Loop
Ad
The Heart of Node.js
The event loop is what lets single-threaded Node handle thousands of concurrent operations. Understanding it explains why Node is fast — and why blocking code is so harmful.
The Core Concept
When Node hits an async operation (file read, DB query, timer), it hands it off to the system and continues running other code. When the operation finishes, its callback is queued and run when the stack is clear.
console.log("1");
setTimeout(() => console.log("2"), 0);
console.log("3");
// Output: 1, 3, 2
// setTimeout callback waits until the stack is empty
The Phases of the Event Loop
- Timers —
setTimeout,setIntervalcallbacks. - Pending callbacks — deferred I/O callbacks.
- Poll — retrieve new I/O events.
- Check —
setImmediatecallbacks. - Close callbacks — e.g. socket close.
Microtasks Run First
console.log("start");
setTimeout(() => console.log("timeout"), 0);
Promise.resolve().then(() => console.log("promise"));
console.log("end");
// Output: start, end, promise, timeout
// Promises (microtasks) run before timers (macrotasks)
Never Block the Loop
// ❌ This freezes the ENTIRE server
function blockingLoop() {
const end = Date.now() + 5000;
while (Date.now() < end) {} // 5s of nothing else running
}
// ✅ Use async APIs instead
await fs.promises.readFile("big.txt");
FAQs
setTimeout(fn, 0) vs setImmediate?
setImmediate runs in the "check" phase, generally after I/O. setTimeout(fn,0) runs in the timers phase. Order can vary outside I/O callbacks.
How do I run CPU-heavy tasks?
Use the worker_threads module to offload them off the main loop. More in our Node.js section.
