Explain the concept of a microtask queue
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.
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?
- 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.
- 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.
- Adding microtasks: Microtasks can be added to the microtask queue using methods like
Promise.resolve().then()andqueueMicrotask().
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 startScript endPromise 1Promise 2setTimeout
In this example:
- The synchronous code (
console.log('Script start')andconsole.log('Script end')) is executed first. - The promise callbacks (
Promise 1andPromise 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
- Promise callbacks: Microtasks are commonly used for promise callbacks to ensure they are executed as soon as possible after the current operation.
- MutationObserver: The
MutationObserverAPI uses microtasks to notify observers of changes in the DOM.
Further reading
- MDN Web Docs: Microtask
- JavaScript Event Loop Explained
- Understanding the JavaScript Microtask Queue