Skip to content

Event Loop Visualizer

Step through the call stack, microtask queue and task queue to see exactly why asynchronous code runs in the order it does.

Intermediate~12 min

What you'll learn

  • Trace how the call stack drains before any queued work runs
  • Distinguish microtasks from macrotasks
  • Predict the output order of mixed sync, promise and timer code

Interactive laboratory

Controls

Run, or step one tick at a time
550 ms
console.log("A");

setTimeout(() => {
  console.log("B");
}, 0);

Promise.resolve().then(() => {
  console.log("C");
});

console.log("D");

Call stack

top first
  • main()

Microtask queue

drained fully

empty

Task queue

one per turn

empty

Output

console

no output yet

Phase
Synchronous script
Steps executed
0
Microtasks run
0
Tasks run
0

What happened?

Script loaded. main() is on the call stack.

Run or step the scenario to watch the stack drain, then the microtask queue, then one task per loop turn.

Why it happened

JavaScript executes on a single thread. The event loop coordinates which piece of work occupies that thread next.

Understanding the ordering rules removes most of the mystery from async bugs, race conditions and 'why did this log last?' surprises.

Key takeaways

  • Microtasks run to exhaustion after every task, before rendering
  • setTimeout(fn, 0) is a scheduling hint, not an immediate call

Tags

  • event loop
  • microtasks
  • async
  • runtime