← Lessons

quiz vs the machine

Gold1400

Concurrency

The Task Queue And Microtask Queue

Two queues with different priorities decide when callbacks and promise reactions actually run.

5 min read · core · beat Gold to climb

Not all callbacks are equal

The event loop does not use one queue but two priority levels. The task queue holds macro tasks such as timers and io callbacks. The microtask queue holds promise reactions and similar high priority work. The order they drain in shapes observable behavior.

The draining rule

After each task runs, the loop drains the entire microtask queue before picking the next task.

  • Run one task from the task queue.
  • Then run all queued microtasks until that queue is empty.
  • Only then take the next task.

This means a resolved promise handler runs before the next timer, even a zero delay timer scheduled earlier.

Why it matters

Microtasks let promise chains complete promptly between tasks, keeping async logic snappy. But there is a hazard. If a microtask keeps queuing more microtasks, the loop can never reach the next task, a condition called microtask starvation. Tasks, by contrast, always yield back to the loop, allowing rendering and io.

Key idea

The loop runs one task then fully drains the microtask queue before the next task, giving promise reactions priority over timers while risking starvation if microtasks endlessly enqueue more.

Check yourself

Answer to earn rating on the learn ladder.

1. When are microtasks drained relative to tasks?

2. Which runs first, a resolved promise handler or a zero delay timer scheduled earlier?

3. What is microtask starvation?