Asyncadvanced
Node.js Event Loop Phases
How Node.js's libuv-based event loop differs from the browser's, with distinct phases for timers, I/O callbacks, and microtasks.
Node's event loop, built on libuv, has an explicitly staged structure with distinct phases, each handling a different category of callback. Backend interviews sometimes go deeper into this than browser-focused ones.
Node's event loop is like hospital ward rounds visiting timers, pending cases, the ER (poll), follow-ups (check), and discharge (close) in strict rotation — but urgent pages (nextTick, then microtasks) get answered immediately between every single patient visit.
Key Concepts
1
Each loop iteration moves through phases in order: timers, pending callbacks, poll (I/O events, can block here waiting for new events), check (setImmediate callbacks), and close callbacks. After each phase and each callback, Node drains the microtask queue completely, plus its own process.nextTick() queue, which runs with even higher priority than regular microtasks.
2
This explains a Node-specific ordering quirk: inside an I/O callback, setImmediate always wins over setTimeout(fn, 0), but at the top level their order isn't guaranteed.
3
process.nextTick() deserves particular attention: excessive or recursive calls can starve the entire event loop, delaying I/O indefinitely — a known real-world footgun explicitly called out in Node's documentation.