JavaScript event loop
Single-threaded runtime that drains a call stack, then a microtask queue, then one macrotask, then repeats forever.
JavaScript runs on one thread. The event loop is the scheduler that decides what runs on that thread next. It is a simple algorithm: run the current task to completion, drain every microtask, render if needed, pick the next task. Repeat.
There are three things to keep separate in your head: the call stack, the microtask queue, and the macrotask queue (the spec calls it the task queue).
- Call stack: where synchronous code runs. Functions push, return pops.
- Microtask queue: promise callbacks,
queueMicrotask,MutationObserver. Drained fully between every task. - Macrotask queue:
setTimeout,setInterval, I/O callbacks, UI events,MessageChannel. One per loop tick.
The rule that trips most people: microtasks run to completion before the next macrotask. If a microtask queues another microtask, that one also runs before any macrotask. You can starve the loop with an infinite microtask chain. setTimeout cannot.
console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");
// 1, 4, 3, 21 and 4 are synchronous. 3 is a microtask queued before the task 2. Microtasks drain before any macrotask fires, even with a 0ms timer.
In the browser, rendering happens between macrotasks, not microtasks. That is why a long microtask chain freezes the page but a chain of setTimeout(fn, 0) does not. requestAnimationFrame callbacks run right before the paint step, which is why you use them for animations instead of setTimeout.
Node.js has the same shape but different macrotask phases (timers, pending, poll, check, close). setImmediate runs in the check phase, setTimeout(fn, 0) in the timers phase. Order between them is not guaranteed when called from the main module, but setImmediate always runs after I/O callbacks in the same tick.
The mental model that locks it in: one task is one unit of work the browser commits to finishing. Microtasks are "finish this thought before doing anything else." Render is "show the user what happened." If you block the task, you block the page.
Learn more
- Talk
- Docs
- DocsHTML spec: Event loopsWHATWG