Ever needed to run a piece of JavaScript code right after the current script finishes, but before the browser does anything else like rendering or handling timer callbacks? Meet queueMicrotask()
!
It's a fundamental part of understanding JavaScript's concurrency model and the Event Loop.
What Does It Do?
In simple terms, queueMicrotask(callback)
schedules a function (callback
) to be executed in the microtask queue. Think of it as saying: "Run this function as soon as the current synchronous block of code is done executing, no matter what, and before handling less urgent things."
The Crucial Timing: Microtasks vs. Macrotasks
This is where queueMicrotask()
shines and differs from something like setTimeout(callback, 0)
. Here's the general flow of the event loop:
- Execute the current synchronous script/task until the call stack is empty.
- Process the Microtask Queue: Execute all functions currently in the microtask queue, one by one, until the queue is empty. New microtasks added during this process are also executed before moving on.
- (Optional: Perform UI rendering updates, if needed and conditions allow).
- Process the Macrotask Queue: Take one task from the macrotask queue (like a
setTimeout
callback,setInterval
, I/O operation, user interaction handler) and execute it. This execution might queue more microtasks. - Repeat from step 2.
Key takeaway: Microtasks (queueMicrotask
, Promise .then
/.catch
/.finally
) have higher priority and run before the next macrotask (setTimeout
, setInterval
, rendering).
Why Use It?
- Fine-grained Control: Perform cleanup or follow-up actions immediately after a block of code finishes, without yielding to the browser's rendering or other macrotasks.
-
Consistency with Promises: Promise callbacks are handled as microtasks. Using
queueMicrotask
allows you to schedule work with the same timing semantics. - Frameworks/Libraries: Useful internally in frameworks or libraries to schedule updates or reactions after state changes but before the browser might repaint.
Quick Example
console.log('Start');
// Macrotask - will run much later
setTimeout(() => {
console.log('setTimeout (Macrotask)');
}, 0);
// Microtask - runs after 'End', before setTimeout
queueMicrotask(() => {
console.log('queueMicrotask (Microtask)');
});
// Promise.then also queues a Microtask
Promise.resolve().then(() => {
console.log('Promise.then (Microtask)');
});
console.log('End');
/*
Expected Output:
---------------
Start
End
queueMicrotask (Microtask)
Promise.then (Microtask)
setTimeout (Macrotask)
*/
Conclusion
queueMicrotask() gives you precise control to schedule code execution immediately after the current task, bypassing the queue for larger tasks like timers or rendering. It's a powerful tool when you need that "as soon as possible, but still async" behavior, especially when working alongside Promises.
It's been 3 (tough) years since I last wrote a post on dev.to and it felt nice writing post again. Will try to maintain streak going ahead.
Top comments (0)