The Event Loop

Advanced · 18 min read · ▶ live playground · ✦ checkpoint

JavaScript runs your entire program — every click handler, every timer, every animation — on one single thread. One thing at a time, ever. And yet the page never freezes while data loads, and a busy app juggles a thousand pending things at once. The machinery that makes that possible is the event loop, and after this lesson you'll be able to predict — exactly — what order any JavaScript code runs in. Interviewers love this question. You're about to love answering it.

One thread, no waiting

The engine executes your code using a call stack — the running function sits on top, whoever called it sits below, and when a function returns it pops off. One stack, one thread: while any function is running, nothing else in JavaScript can run. No exceptions.

That sounds like a disaster. A network request takes 300 milliseconds — surely everything freezes? It doesn't, because of a crucial division of labor: slow things aren't done by your thread. When you call setTimeout, the runtime (the browser machinery around the engine) starts the clock. Your function returns instantly; the stack empties; the page stays alive. The same goes for network requests and file reads — the runtime does the waiting, off to the side.

When the timer finishes, the runtime doesn't barge in and interrupt your code — it can't; there's only one thread. Instead it puts your callback in a queue. And the event loop is the simple rule tying it together:

If the call stack is empty, take the next callback from the queue and run it. Repeat, forever.

That's the whole trick. JavaScript "handles a million things at once" by never actually waiting for any of them — it just leaves a callback to be queued when each thing finishes.

Why setTimeout(fn, 0) doesn't run now

Read the loop's rule again and a famous puzzle solves itself. A zero-millisecond timer doesn't mean "run this immediately" — it means "queue this immediately." The callback still has to wait for two things: the stack to empty (all currently-running code finishes), and its turn in the queue.

console.log("first");
setTimeout(() => console.log("third — even at 0ms!"), 0);
console.log("second");

first, second, third — even at 0ms! The timer callback queues instantly but runs only after the whole script — one task — finishes.

So setTimeout(fn, 0) really means "as soon as you're free." And a delay of 1000 means "no sooner than a second — maybe later, if the thread is busy." Timers are promises of scheduling, not guarantees of punctuality.

setTimeout(() => console.log("task"), 0);
 
Promise.resolve()
  .then(() => console.log("microtask 1"))
  .then(() => console.log("microtask 2"));

microtask 1, microtask 2, task — both microtasks (even the one created mid-drain) run before the timer gets its turn.

Try it — the interview classic

Four lines, four different destinations. Predict the output order before you run it — say it out loud — then check yourself. This exact snippet, in some costume, appears in half of all JavaScript interviews.

javascript — live consolereal engine
⌘/Ctrl + Enter to run

Walk it: the script itself is the first task. Lines 1 and 2 of output are the synchronous console.logs — the stack must empty before anything queued can run. Then the microtask queue drains: the promise callback prints 3. Only then does the task queue advance: the timer prints 4. Sync → microtasks → tasks. Every time.

The loop can starve — and now you know why

One thread means one loose loop can block everything. Watch the timer wait while the stack is busy:

javascript — live consolereal engine
⌘/Ctrl + Enter to run

The 0-millisecond timer fires after the 200-millisecond hog, because the event loop only runs callbacks when the stack is empty. In a browser this is why heavy synchronous work freezes the page — clicks queue up behind your loop, helpless. The professional consequences land in Part IV (keep handlers small) and lesson 18.3 (move heavy work to a worker thread).

You now hold the mental model the rest of asynchronous JavaScript stands on. Next: this — the other question interviewers can't resist.

Checkpoint

Answer all three to mark this lesson complete

+50 XP on completion