How it works
The explanation, with examples you can run.
One pass of the loop
- Timers: callbacks of
setTimeoutandsetIntervalwhose time has come. - Pending callbacks: a few system-level callbacks deferred from the previous pass.
- Poll: waits for I/O and runs its callbacks (incoming data, finished file reads). If nothing else is scheduled, Node waits here.
- Check:
setImmediatecallbacks. - Close callbacks: for example a socket's
closeevent.
Between any two callbacks, in any phase, Node empties the process.nextTick queue and then the promise microtask queue. (Before Node 11 this happened only between phases.)
Timeout or immediate?
// order.mjs (run with: node order.mjs)import { readFile } from "node:fs" readFile(import.meta.filename, () => { setTimeout(() => console.log("timeout"), 0) setImmediate(() => console.log("immediate"))})// Always prints: immediate, timeoutInside an I/O callback the loop is in the poll phase, and check comes next, so the immediate wins every time. From the main script the order depends on timing, as the quiz below explains. A setTimeout delay of 0 is treated as 1 ms.
When the loop stops
Node keeps looping while there is something that could still call you back: a pending timer, an open server or socket, a running child process. When nothing is left, the process exits. timer.unref() and server.unref() let Node exit even if those are still around.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.