We delve deeply into the intriguing realm of JavaScript’s internal workings in this article, emphasising the crucial distinctions between microtasks and macrotasks. Writing efficient, non-blocking programs requires an understanding of how the event loop prioritises jobs, how microtasks can block macrotasks if not managed appropriately, and more. Ideal for developers that want to improve their real-world app performance and responsiveness!
What are Microtasks?
Operations that are planned to run after the presently running script concludes but before the browser renders anything or handles any macrotasks are known as microtasks.
Common instances of microtasks include:
Promise.thencallbacksqueueMicrotaskMutationObservercallbacks
They are crucial for fine-tuning asynchronous behaviour inside your JavaScript code.
What are Macrotasks?
Scheduled actions known as macrotasks (or “tasks”) are added to the task queue and run once the current call stack has been cleared.
Examples include:
setTimeoutsetIntervalsetImmediate(Node.js)- UI events like
click,keydown XHRcallbacks
Each macrotask gives the browser a chance to repaint the screen and handle user interactions between tasks.
Getting Started with the Event Loop
The Event Loop is the mechanism that coordinates microtasks and macrotasks.
Understanding how it works is key to mastering asynchronous JavaScript.
At a high level:
- JavaScript executes the current stack.
- Once the stack is empty, all microtasks are run.
- The next macrotask pulls and carries out the task.
- Repeat!
Installation (Setting Up a Demo)
You don’t need to install anything to investigate the differences between microtasks and macrotasks.
Launch the Console in your browser and try a basic example like:
console.log('Start');
setTimeout(() => {
console.log('Macrotask: setTimeout');
}, 0);
Promise.resolve().then(() => {
console.log('Microtask: Promise');
});
console.log('End');
Expected Output:
Start
End
Microtask: Promise
Macrotask: setTimeout
Defining a Simple Task Queue To Understand Microtasks and Macrotasks
Simulate a simple version of the Event Loop to observe how jobs are handled:
const macrotasks = [];
const microtasks = [];
function run() {
while (microtasks.length) {
const task = microtasks.shift();
task();
}
if (macrotasks.length) {
const task = macrotasks.shift();
task();
setTimeout(run, 0);
}
}
This is, very roughly, how JavaScript prioritizes tasks internally!
Understanding the Event Loop’s Core Concepts
1. Microtask Queue
- It processes after the current script and before any rendering or macrotask.
- It completes draining before moving to the next macrotask.
- Queuing too many microtasks causes long blocking.
2. Macrotask Queue
- It runs after clearing the microtasks.
- Browser can repaint UI between macrotasks.
- These tasks are for situations where there is no immediate need, like user interactions.
3. Prioritization of Tasks
- Microtasks > Macrotasks
- Microtasks that keep adding more microtasks can starve macrotasks.
- You should avoid an infinite microtask chain to prevent blocking the UI.
4. Real-world Examples
Example of a microtask inside a macrotask:
setTimeout(() => {
console.log('Macrotask');
Promise.resolve().then(() => console.log('Microtask inside Macrotask'));
}, 0);
Output:
Macrotask
Microtask inside Macrotask
Conclusion
To write efficient, non-blocking code, you need to understand the distinctions between microtasks and macrotasks and how they work together within the JavaScript Event Loop.
Gaining proficiency in this area aids in bug prevention, responsiveness enhancement, and better architectural choices in practical applications!
For more such blogs and updates follow Front-end Competency.
Follow NashTech Blogs for more amazing blogs.