The JavaScript Event Loop Explained

JavaScript is single-threaded, yet handles thousands of concurrent operations (network requests, timers, UI events) without blocking — the event loop is the mechanism that makes this possible.

console.log('1: sync');

setTimeout(() => console.log('2: macrotask (setTimeout)'), 0);

Promise.resolve().then(() => console.log('3: microtask (promise)'));

console.log('4: sync');

// Actual output order: 1, 4, 3, 2
// Sync code runs first, THEN all microtasks (promises),
// THEN macrotasks (setTimeout) - even with a 0ms delay

The Core Model

The call stack runs synchronous code to completion first. Once it’s empty, the event loop drains the entire microtask queue (Promises, queueMicrotask) before processing even a single macrotask (setTimeout, I/O events) — this ordering is exactly why a setTimeout(fn, 0) never actually runs immediately, even though the delay is zero.