JS Sketchbooksee JavaScript think ✏️
← back to phase 6

6.2 — The event loop

Last lesson ended on a cliffhanger: the timer rings off the thread — so how does its callback get back onto the one and only stack without crashing into whatever's running? The answer is the most famous diagram in JavaScript: the event loop.

Four parts, one rule. The call stack you know. The Web APIs — the environment's waiting room where timers tick and network replies land.

The callback queue — a first-in-first-out line of callbacks ready to run. And the event loop itself, a tireless arm with a single rule: is the stack empty? Then move exactly one callback from the queue onto it.

Learn this machine and setTimeout(fn, 0) stops being a riddle forever.

watch it happen
console.log("1");

setTimeout(() => {
  console.log("3");
}, 0);

console.log("2");

Meet the machine, four parts. The call stack — the ONLY place JavaScript executes. The Web APIs — the environment’s own machinery, running on separate threads. The callback queue — a first-in-first-out waiting line. And the event loop — an arm that checks one thing, forever. Nothing is moving yet.

call stackglobalWeb APIs — the waiting roomcallback queue (first in, first out)the event loop: “stack empty? → move ONE”four parts: the stack (JS runs here), the Web APIs (theenvironment), the callback queue, and the loop connecting them(console: nothing yet)
under the hood

The deeper story, with the real names for things — this part is what turns “I saw it” into “I can explain it.”

Where do clicks fit? Same machine, no special case: the browser watches the mouse (Web-API side), and a click puts your handler in the queue. That's why 6.1's blocked page had dead buttons — the handlers were queued behind a stack that never emptied. Every "later" in the browser — timers, clicks, network replies, even Playwright's simulated events — is a callback taking its turn through this one queue.

💼 On the job — the event loop is not part of the JavaScript engine. V8 has the stack and heap; the loop, timers and queue live in the environment — the browser here; Node's version arrives in 9.6.

Also the queue is honest FIFO: two timers with equal delay run in scheduling order — your exercise proves it.

One seat is still empty in this diagram: promises (lesson 6.4) don't use this queue — they get a faster one. That's lesson 6.5, and it's the last piece of the machine.

your turn

⌨️ the ticket counter

Choreograph four prints so the output proves you can predict the machine: two scheduled callbacks must both wait for ALL the sync code — and keep their queue order.

requirements:

  • Print "opens".
  • Schedule (0ms) a print of "ticket 1 served", then schedule (0ms) a print of "ticket 2 served".
  • Print "queue forms". Required output order: opens, queue forms, ticket 1 served, ticket 2 served — sync first, then the queue in first-in-first-out order.

when you press RUN, the console must show exactly:

opens
queue forms
ticket 1 served
ticket 2 served

✏️ Quick check 1

Type the FULL output order, separated by spaces:

console.log("a");
setTimeout(() => console.log("b"), 0);
console.log("c");

✏️ Quick check 2

The event loop moves a callback onto the stack only when the stack is ___. Type the word.

✏️ Quick check 3

A click happens while your code runs a long sync loop. Where does the click’s handler wait — the stack, or the queue? Type it.

teach it back

🗣️ Now teach it back

The interview favorite: “Explain the event loop.” Name the four parts, the one rule, and use setTimeout(fn, 0) as your worked example — including why its callback can never run before the sync code finishes.

Write it as if your friend is sitting next to you. Saved to your journal — future-you will use these notes to teach others.

a few sentences, minimum — you’ve got this
to remember
Four parts: call stack (JS runs here) · Web APIs (environment waits here) · callback queue (FIFO) · the loop.
ONE rule: stack empty → move one callback from queue to stack. Nothing ever interrupts running code.
setTimeout(fn, 0) = “queue it now”: all sync code first, then the callback. Blocking starves the queue — dead buttons, frozen pages.