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.

Call Stack
Execution Log
Microtask Queue
Macrotask Queue

Try These Examples

  • Classic ordering — sync + Promise.then + setTimeout to see microtasks beat macrotasks
  • Multiple microtasks — three Promise callbacks queued before one setTimeout
  • Interleaved 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(), and queueMicrotask().
  • Macrotask queue — holds callbacks from setTimeout, setInterval, and browser I/O events.

The event loop follows a strict order each cycle:

  1. Execute whatever is on the call stack until it is empty.
  2. Drain all pending microtasks (including any new ones added during this phase).
  3. Pick one macrotask and push it onto the call stack.
  4. 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.

Related Tools

← Back to all tools