Skip to content
Optimal Lab

Frontend · interactive

The browser event loop

Predict the output before you press play. One thread runs your script, then every queued microtask, then (maybe) a render, then the next task. A promise callback always beats a zero-millisecond timer.

console.log('A')
setTimeout(() => console.log('B'), 0)
Promise.resolve().then(() => console.log('C'))
queueMicrotask(() => console.log('D'))
console.log('E')

Call stack

  • script

Microtasks

  • empty

Tasks

  • empty

Render step

waiting for an empty stack and microtask queue

console: —

The script starts running on the call stack.

step 1 of 11
1

Run the script to the end

Synchronous code runs first, start to finish. Timers and promises only queue callbacks.

A, E

2

Drain every microtask

Promise callbacks and queueMicrotask run next, all of them, including any they add. Loop forever here and the page freezes.

C, D

3

Render if a frame is due

Style, layout and paint happen between tasks, about every 16 ms. Long tasks delay them: that's jank.

requestAnimationFrame callbacks run here.

4

Take one task from the queue

Timers, clicks and network callbacks are tasks. One runs, then microtasks again, then maybe a render.

Output: A E C D B

In production

Tools and technologies

Every browser follows the same HTML event loop spec.

Not tied to one language — use these names when you search docs or design a system.