Read first
The event loop is how a single-threaded runtime like JavaScript handles many things in progress at once. Slow work (timers, network, files) is done outside your code; when it finishes, a callback waits in a queue, and the event loop runs it only when the call stack is empty.
How it works
One turn of the loop in a browser, as the HTML Standard describes it:
- Run the oldest task from a task queue until the call stack is empty.
- Run every microtask, including microtasks added while doing so, until the microtask queue is empty.
- If it is time to render:
requestAnimationFramecallbacks, style, layout, paint. - Repeat.
flowchart TD T["Take ONE task<br/>(timer, click, I/O, the script)"] --> R["Run it until the<br/>call stack is empty"] R --> M{"Microtask queue<br/>empty?"} M -- no --> RM["Run the next microtask<br/>(.then, await, queueMicrotask)"] RM --> M M -- yes --> P{"Time to render?<br/>(~every 16.7 ms)"} P -- yes --> D["requestAnimationFrame,<br/>style, layout, paint"] P -- no --> T D --> T
The small inner loop (microtasks) must finish completely before the big loop can paint or take another task.
Node.js uses the same idea but with named phases (timers, poll for I/O, check for setImmediate, close callbacks),
and runs process.nextTick callbacks and promise microtasks between callbacks.
Example
setTimeout(() => console.log('task'), 0);
Promise.resolve().then(() => console.log('microtask'));
console.log('sync');
// sync
// microtask
// taskTraps
setTimeout(fn, 0)is a minimum delay, not “now”.- Endless microtasks starve rendering; endless tasks do not.
- Heavy synchronous code blocks everything. Move it to a Web Worker or split it into chunks.
Related
Lesson: #1 · The event loop. Spec: HTML Standard: event loops.
Check yourself
What has to be true before a queued callback can run?
The call stack must be empty. Then all microtasks run first, and only after that the next task.
Why can a page stay responsive while it waits for a network request?
The request is handled by the browser outside the JavaScript thread. The thread is free until the response’s callback is queued and run.
Leads to
- HTML Standard: event loops: The section of the HTML Standard (WHATWG) that defines how browsers run tasks, microtasks and rendering.
- Promise: An object that stands for a result that isn’t ready yet. It is pending, then fulfilled with a value or rejected with an error, exactly once.
- Task queue: Where callbacks for timers, events and I/O wait. The event loop runs one task per turn, then all microtasks.
- Web Worker: A real background thread for JavaScript in the browser. It has no DOM access and talks to the page by passing messages.