Guides/JavaScript Event Loop: Microtasks vs Macrotasks

JavaScript Event Loop: Microtasks vs Macrotasks

The interview classic: why Promise callbacks beat setTimeout(0) — and how to see it happen.

JavaScript is single-threaded. Synchronous code runs to completion on the call stack. Asynchronous work is scheduled onto queues. The event loop decides what runs next when the stack is empty.

Microtasks vs macrotasks

Microtasks include Promise reactions (.then, queueMicrotask). Macrotasks include setTimeout, setInterval, and many I/O callbacks.

After each turn of synchronous work, the engine drains all queued microtasks before taking the next macrotask. That is why this prints Promise logs before the timer:

console.log("Start");
setTimeout(() => console.log("timeout"), 0);
Promise.resolve().then(() => console.log("then"));
console.log("End");
// Start → End → then → timeout

See it visually

Use the JavaScript Execution Visualizer to step through call stack, microtask queue, and timer queue. The default demo matches Node's console order for chained .then callbacks.

FAQ

Do microtasks always run before setTimeout?

Yes for the classic case: after the current call stack clears, the engine drains the microtask queue completely before the next macrotask (including setTimeout 0).

Are Promise.then callbacks microtasks?

Yes. Promise reactions are queued as microtasks. That is why they often log before a zero-delay timer.

Try it live

Open the matching StackTools utility — runs in your browser.

Open JS Execution Visualizer