What is the difference between microtasks and macrotasks?
Both are queues of asynchronous callbacks, but microtasks have higher priority.
Microtasks — Promise callbacks (.then/.catch), queueMicrotask, await continuations. The whole queue drains after each task.
Macrotasks — setTimeout, setInterval, events, I/O. Only one runs per event-loop iteration.
Key rule: after any task, all microtasks run before the next macrotask — so a resolved Promise always beats setTimeout(0).
console.log('1: sync');
setTimeout(() => console.log('2: macrotask'), 0);
Promise.resolve()
.then(() => console.log('3: microtask 1'))
.then(() => console.log('4: microtask 2'));
queueMicrotask(() => console.log('5: microtask 3'));
console.log('6: sync');
// Output:
// 1: sync
// 6: sync
// 3: microtask 1
// 5: microtask 3
// 4: microtask 2
// 2: macrotask
// Microtask starvation
function starveMacrotasks() {
Promise.resolve().then(() => {
console.log('microtask');
starveMacrotasks(); // Recursive — setTimeout NEVER fires
});
}
// starveMacrotasks(); setTimeout(() => console.log('never'), 0);Sync code runs first (1, 6). Then ALL microtasks drain (3, 5, 4) — note that microtask 2 (.then chain) runs before the macrotask even though it was scheduled after.
Only after ALL microtasks are drained does the macrotask (2) run. The starvation example: recursive microtasks prevent setTimeout from ever executing.
The execution order output question is the #1 event loop interview question. Rule: ALL microtasks drain before the next macrotask.
Promise.then = microtask, setTimeout = macrotask. The starvation example shows deep understanding.