Microtasks vs. Macrotasks in JavaScript

Microtasks vs. Macrotasks in JavaScript

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

  1. Promise Callbacks Always Execute Before setTimeout Callbacks

    • If you need something to run before the next event loop cycle, use Promises instead of setTimeout.
  2. Avoid Blocking Microtasks

    • If a microtask continuously queues another microtask, it can block macrotasks, leading to a UI freeze.
  3. Performance Optimization

    • Use queueMicrotask() for high-priority background tasks instead of setTimeout(fn, 0).

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.