JavaScript path · Under the hood · Topic 12 of 12

Node's event loop

Not started

Node's loop, provided by libuv, cycles through phases: timers, pending callbacks, poll (where I/O completes), check (setImmediate) and close callbacks. After every single callback Node first drains process.nextTick callbacks, then promise microtasks. Browsers have no nextTick or setImmediate, but share the task-then-microtasks rule.

Why it matters: It explains surprises such as setTimeout(fn, 0) and setImmediate(fn) running in either order from the main script.

1

How it works

The explanation, with examples you can run.

One pass of the loop

  1. Timers: callbacks of setTimeout and setInterval whose time has come.
  2. Pending callbacks: a few system-level callbacks deferred from the previous pass.
  3. Poll: waits for I/O and runs its callbacks (incoming data, finished file reads). If nothing else is scheduled, Node waits here.
  4. Check: setImmediate callbacks.
  5. Close callbacks: for example a socket's close event.

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, timeout

Inside 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.

2

Check yourself

3 questions. Get them all right to finish this topic.

  1. 1.Inside an fs.readFile callback you call setTimeout(f, 0) and then setImmediate(g). Which runs first?
  2. 2.From the main script, the same pair runs in which order?
  3. 3.When does a Node process exit on its own?

0 of 3 right so far. Get all three to finish this topic.