Event Loop Visualiser
See how the JavaScript event loop decides what runs and when. Add tasks to the call stack and queues, then step through execution to understand why Promise callbacks always run before setTimeout.
Try These Examples
Classic ordering— sync + Promise.then + setTimeout to see microtasks beat macrotasksMultiple microtasks— three Promise callbacks queued before one setTimeoutInterleaved tasks— mix of sync, micro, and macrotasks to trace full execution
How It Works
JavaScript is single-threaded, meaning only one piece of code runs at a time on the call stack. When asynchronous operations complete, their callbacks are not executed immediately. Instead, they are placed into one of two queues:
- Microtask queue — holds callbacks from Promise
.then(),.catch(),.finally(), andqueueMicrotask(). - Macrotask queue — holds callbacks from
setTimeout,setInterval, and browser I/O events.
The event loop follows a strict order each cycle:
- Execute whatever is on the call stack until it is empty.
- Drain all pending microtasks (including any new ones added during this phase).
- Pick one macrotask and push it onto the call stack.
- Repeat from step 1.
This is why a Promise.resolve().then(cb) callback always runs before a setTimeout(cb, 0) callback, even though both are scheduled "immediately".
Example Execution Order
console.log('1: sync');
setTimeout(() => console.log('2: timeout'), 0);
Promise.resolve().then(() => console.log('3: promise'));
console.log('4: sync');
// Output order: 1: sync, 4: sync, 3: promise, 2: timeout
The two synchronous console.log calls run first (call stack). Then the Promise callback runs (microtask queue is drained). Finally the setTimeout callback runs (macrotask queue).
Frequently Asked Questions
What is the JavaScript event loop?
The event loop is the mechanism that allows JavaScript to perform non-blocking operations despite being single-threaded. It continuously checks whether the call stack is empty and, if so, picks the next task from the microtask or macrotask queues to execute.
Why do Promise callbacks run before setTimeout callbacks?
Promise callbacks are placed in the microtask queue, while setTimeout callbacks go into the macrotask queue. After each task completes on the call stack, the event loop drains all microtasks before picking the next macrotask. This is why Promise callbacks always run before setTimeout callbacks that were scheduled at the same time.
Is this an exact simulation of a browser's event loop?
This tool is a simplified educational model. Real browser event loops also handle rendering steps, requestAnimationFrame callbacks, and multiple task sources. However, the core ordering rules demonstrated here — call stack first, then all microtasks, then one macrotask — accurately represent the specification.
What is the difference between microtasks and macrotasks?
Microtasks include Promise callbacks (.then, .catch, .finally) and queueMicrotask() calls. Macrotasks include setTimeout, setInterval, and I/O callbacks. The key difference is scheduling priority: all pending microtasks are drained before the next macrotask runs.