The Event Loop — Why setTimeout(fn, 0) Doesn't Execute Immediately
Execution order of Call Stack, Task Queue, and Microtask Queue
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// Output: 1, 4, 3, 2
Why does 0ms timeout come after Promise? Event loop execution order.
3 Queues
Call Stack — currently executing function. Sync code runs here sequentially.
Microtask Queue — Promise.then, MutationObserver, queueMicrotask. When Call Stack empties, all Microtasks drain completely before anything else. Priority over Task Queue.
Task Queue (Macro Task) — setTimeout, setInterval, I/O callbacks, requestAnimationFrame. One at a time, only after Microtasks are fully drained.
V8 Implementation
V8 itself doesn't implement the event loop. Browsers use libevent/OS event loop; Node.js uses libuv. V8 only manages Call Stack and Microtask Queue.
setTimeout(fn, 0) minimum delay is actually 4ms in browsers (HTML spec).
Key Points
All sync code on Call Stack must finish before async callbacks execute
Microtasks (Promise.then) always execute before Tasks (setTimeout)
Microtask Queue drains completely — no Tasks interleaved
V8 manages only Call Stack + Microtasks; event loop is browser/libuv responsibility