Home > Web Front-end > JS Tutorial > Deep Dive in Asynchrony: Microtasks, Macrotasks, and the Event Loop

Deep Dive in Asynchrony: Microtasks, Macrotasks, and the Event Loop

Linda Hamilton
Release: 2025-01-01 08:23:10
Original
980 people have browsed it

Deep Dive in Asynchrony: Microtasks, Macrotasks, and the Event Loop

JavaScript’s asynchronous nature can feel like magic until you dive into the mechanics. The secret sauce lies in its event loop, which orchestrates two key players: microtasks and macrotasks. But what are they, how do they work, and why do they matter? Let’s unravel the mystery with a deep dive, examples, and tips to master this concept.


The Event Loop and Task Queues

The JavaScript engine executes code in a single thread. To handle asynchronous operations, it relies on the event loop, which coordinates between the call stack and task queues. These task queues are split into two categories: microtasks and macrotasks.

Microtasks

Microtasks are high-priority tasks that must be executed as soon as the currently executing JavaScript code finishes and the call stack is empty. They ensure quick follow-up actions and consistent states. Common examples include:

  • Promises (.then, async/await)
  • MutationObserver callbacks

Macrotasks

Macrotasks are lower-priority tasks that the event loop handles only after all microtasks have been executed. They handle larger, deferred operations and external events. Common examples include:

  • Timers (setTimeout, setInterval)
  • MessageChannel callbacks
  • I/O operations

There’s also requestAnimationFrame, which isn’t part of either queue. It synchronizes with the browser’s rendering cycle, making it ideal for smooth animations.


How It Works

Here’s how the event loop processes tasks:

  1. Executes synchronous code first.
  2. Clears the microtask queue.
  3. Executes one task from the macrotask queue.
  4. Repeats steps 2 and 3 until all tasks are handled.

This prioritization ensures that high-priority tasks like promises are resolved before less urgent operations like timers.


An Example in Action

Below is a practical code snippet to illustrate the interaction between synchronous code, microtasks, macrotasks, and requestAnimationFrame:

console.log('Synchronous code starts');

// Macrotask: setTimeout
setTimeout(() => {
  console.log('Macrotask: setTimeout');
}, 0);

// Macrotask: setInterval
const intervalId = setInterval(() => {
  console.log('Macrotask: setInterval');
  clearInterval(intervalId);
}, 100);

// Microtask: Promise
Promise.resolve().then(() => {
  console.log('Microtask: Promise then 1');
  Promise.resolve().then(() => {
    console.log('Microtask: Promise then 2');
  });
});

// Microtask: MutationObserver
const observer = new MutationObserver(() => {
  console.log('Microtask: MutationObserver');
});
const targetNode = document.createElement('div');
observer.observe(targetNode, { attributes: true });
targetNode.setAttribute('data-test', 'true');

// Macrotask: MessageChannel
const channel = new MessageChannel();
channel.port1.onmessage = () => {
  console.log('Macrotask: MessageChannel');
};
channel.port2.postMessage('Test');

// requestAnimationFrame
requestAnimationFrame(() => {
  console.log('Outside task queues: requestAnimationFrame');
});

console.log('Synchronous code ends');
Copy after login

Expected Output

The output sequence helps clarify the prioritization:

  1. Synchronous Code: “Synchronous code starts”, “Synchronous code ends”
  2. Microtasks:
    • “Microtask: Promise then 1”
    • “Microtask: Promise then 2”
    • “Microtask: MutationObserver”
  3. Macrotasks:
    • “Macrotask: setTimeout”
    • “Macrotask: MessageChannel”
    • “Macrotask: setInterval”
  4. requestAnimationFrame: “Outside task queues: requestAnimationFrame”

Deep Dive: Microtasks vs. Macrotasks

Microtasks: Key Characteristics

  • Execute immediately after the synchronous code completes.
  • Ideal for small, high-priority updates like resolving promises or reacting to DOM mutations.
  • Examples: Promises, MutationObserver.

Macrotasks: Key Characteristics

  • Run only after all microtasks are cleared.
  • Used for larger, lower-priority operations or external event handling.
  • Examples: Timers, MessageChannel.

requestAnimationFrame: The Odd One Out

Though not part of the task queues, requestAnimationFrame plays a unique role in asynchrony. It schedules code to run before the next browser repaint, ensuring minimal frame drops and smoother animations.


Conclusion

The interplay between microtasks, macrotasks, and the event loop is at the heart of JavaScript’s asynchrony. By understanding and leveraging these concepts, you can write more efficient, maintainable, and performant code. Remember: microtasks first, macrotasks second, and requestAnimationFrame for visual polish. Happy coding!

The above is the detailed content of Deep Dive in Asynchrony: Microtasks, Macrotasks, and the Event Loop. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template