JavaScript is a single-threaded language that uses an event loop to handle asynchronous operations efficiently. Understanding the difference between Microtasks and Macrotasks is crucial for writing optimized and predictable asynchronous code.
What are Microtasks?
Microtasks are high-priority tasks that execute immediately after the currently executing script completes, before any rendering updates or macrotasks. They include:
Promises (
.then
,.catch
,.finally
)queueMicrotask()
Mutation Observer
Example of Microtasks:
console.log("Start");
Promise.resolve().then(() => {
console.log("Microtask 1");
}).then(() => {
console.log("Microtask 2");
});
console.log("End");
Output:
Start
End
Microtask 1
Microtask 2
The microtasks execute right after the synchronous code finishes but before any macrotasks.
What are Macrotasks?
Macrotasks are lower-priority tasks that execute after microtasks and rendering updates. They include:
setTimeout
,setInterval
,setImmediate
(Node.js)requestAnimationFrame
MessageChannel
I/O operations (e.g., fetching data)
Example of Macrotasks:
console.log("Start");
setTimeout(() => {
console.log("Macrotask");
}, 0);
console.log("End");
Output:
Start
End
Macrotask
The setTimeout
callback runs after the synchronous code finishes because it is a macrotask.
Microtasks vs. Macrotasks Execution Order
Microtasks always run before macrotasks in the event loop. Consider this example:
console.log("Start");
setTimeout(() => {
console.log("Macrotask");
}, 0);
Promise.resolve().then(() => {
console.log("Microtask");
});
console.log("End");
output:
Start
End
Microtask
Macrotask
Even though setTimeout
is set with a delay of 0ms
, it still gets queued in the macrotask queue, which executes after microtasks.
Practical Implications
Promise Callbacks Always Execute Before setTimeout Callbacks
- If you need something to run before the next event loop cycle, use Promises instead of
setTimeout
.
- If you need something to run before the next event loop cycle, use Promises instead of
Avoid Blocking Microtasks
- If a microtask continuously queues another microtask, it can block macrotasks, leading to a UI freeze.
Performance Optimization
- Use
queueMicrotask()
for high-priority background tasks instead ofsetTimeout(fn, 0)
.
- Use
Conclusion
Microtasks are processed before macrotasks, making them useful for handling short, high-priority asynchronous operations. Understanding this execution order helps avoid performance bottlenecks and write efficient, non-blocking JavaScript code.