DEV Community

Cover image for ๐Ÿ“š Understanding the Event Loop in JavaScript: Macrotasks and Microtasks Explained
Artem Turlenko
Artem Turlenko

Posted on

๐Ÿ“š Understanding the Event Loop in JavaScript: Macrotasks and Microtasks Explained

JavaScript is known for its single-threaded nature, yet it handles asynchronous operations efficiently. This is made possible by the event loop, which manages the execution of synchronous code, asynchronous callbacks, and promises. To fully understand how JavaScript handles asynchronous code, you need to know about macrotasks and microtasks.

In this post, weโ€™ll explore the event loop, how macrotasks and microtasks work, and how they affect the execution of your JavaScript code.


๐Ÿ”„ What is the Event Loop?

The event loop is the mechanism that allows JavaScript to perform non-blocking operations by offloading tasks to the browser or runtime environment and executing them when the main thread is free.

Key Points:

  • JavaScript runs code in a single thread.
  • The event loop coordinates between the call stack, task queue, and microtask queue.
  • It ensures that tasks are executed in the correct order, maintaining smooth application performance.

โšก Macrotasks vs Microtasks

๐Ÿ•“ Macrotasks

Macrotasks include:

  • setTimeout
  • setInterval
  • setImmediate (Node.js)
  • I/O tasks
  • UI rendering tasks

When Are They Executed?

  • Macrotasks are queued in the task queue.
  • After the call stack is empty, the event loop picks the first macrotask and executes it.

Example:

console.log('Script start');

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

console.log('Script end');
Enter fullscreen mode Exit fullscreen mode

Output:

Script start
Script end
Macrotask: setTimeout
Enter fullscreen mode Exit fullscreen mode

โšก Microtasks

Microtasks include:

  • Promises (.then, .catch, .finally)
  • process.nextTick() (Node.js)
  • MutationObserver

When Are They Executed?

  • Microtasks are queued in the microtask queue.
  • After each operation on the call stack completes, all microtasks in the queue are executed before any macrotask is processed.

Example:

console.log('Script start');

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

console.log('Script end');
Enter fullscreen mode Exit fullscreen mode

Output:

Script start
Script end
Microtask: Promise.resolve
Enter fullscreen mode Exit fullscreen mode

๐Ÿ” Macrotasks vs Microtasks: Execution Order

Letโ€™s see how they interact:

console.log('Script start');

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

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

console.log('Script end');
Enter fullscreen mode Exit fullscreen mode

Output:

Script start
Script end
Microtask: Promise.resolve
Macrotask: setTimeout
Enter fullscreen mode Exit fullscreen mode

Why? Because:

  1. Synchronous code runs first.
  2. After the call stack is empty, all microtasks are processed.
  3. Only then are macrotasks executed.

๐Ÿƒ Real-World Example: Understanding Task Prioritization

console.log('Script start');

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

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

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

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

console.log('Script end');
Enter fullscreen mode Exit fullscreen mode

Output:

Script start
Script end
Microtask: Promise 1
Microtask: Promise 2
Macrotask: setTimeout 1
Macrotask: setTimeout 2
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ Key Takeaways

  • Synchronous code runs first.
  • Microtasks are processed after each synchronous operation and before any macrotask.
  • Macrotasks are executed one at a time after microtasks have cleared.
  • Misunderstanding task order can lead to unexpected results, especially when dealing with promises and timers.

โœจ Conclusion

Understanding the event loop, along with the behavior of macrotasks and microtasks, is essential for writing efficient and bug-free JavaScript code. It ensures you manage asynchronous operations correctly, optimize performance, and avoid tricky bugs.

๐Ÿ’ฌ What challenges have you faced with the event loop? Share your experiences in the comments! ๐Ÿš€

Top comments (0)