Quiz

Explain the concept of a microtask queue

Topics
AsyncJavaScript

TL;DR

The microtask queue holds callbacks such as promise reactions, queueMicrotask() callbacks, and MutationObserver notifications. At a microtask checkpoint—normally after the current task or callback finishes and the JavaScript stack is empty—the runtime drains the queue before it may render and select another task. Microtasks queued by other microtasks are drained in the same checkpoint, so recursively adding them can starve rendering and other work.


Microtask checkpoint

After a task finishes, the runtime drains microtasks until the queue is empty, including microtasks added by other microtasks.

Microtask checkpoint between browser tasks

Because the queue drains recursively, an unbounded microtask chain can postpone timers, input handling, and rendering.

The concept of a microtask queue

What is a microtask queue?

The microtask queue is part of the host's event-loop machinery. It holds work such as promise reactions, queueMicrotask() callbacks, and MutationObserver notifications. Browsers perform a microtask checkpoint after a task or callback finishes when the JavaScript stack is empty, and at other points defined by the HTML standard.

How does the microtask queue work?

  1. Execution order: After the current task finishes, the runtime drains pending microtasks before it selects another task and normally before the browser gets an opportunity to render.
  2. Queue draining: If a microtask queues another microtask, the new one runs in the same checkpoint. An unbounded chain can therefore delay timers, input, and rendering.
  3. Adding microtasks: Microtasks can be added to the microtask queue using methods like Promise.resolve().then() and queueMicrotask().

Example

Here is an example to illustrate how the microtask queue works:

console.log('Script start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
Promise.resolve()
.then(() => {
console.log('Promise 1');
})
.then(() => {
console.log('Promise 2');
});
console.log('Script end');

Output:

Script start
Script end
Promise 1
Promise 2
setTimeout

In this example:

  • The synchronous code (console.log('Script start') and console.log('Script end')) is executed first.
  • The promise callbacks (Promise 1 and Promise 2) are added to the microtask queue and executed next.
  • The timer schedules a task, which can run only after the current task and its microtask checkpoint have completed.

Use cases

  1. Promise callbacks: Microtasks are commonly used for promise callbacks to ensure they are executed as soon as possible after the current operation.
  2. MutationObserver: The MutationObserver API uses microtasks to notify observers of changes in the DOM.

Further reading

Exercises

Check your understanding
Beta
Check your understanding Exercise 1 of 2
Check your understanding Exercise 1 of 2

What is the log order?

console.log('A');
setTimeout(() => console.log('D'), 0);
Promise.resolve().then(() => console.log('B'));
queueMicrotask(() => console.log('C'));
console.log('E');