Understanding the Call Stack, Microtask Queue, and Macrotask Queue in JavaScript
1. Definitions and Functions
Call Stack: The Call Stack is a data structure used by JavaScript to manage execution contexts. When a function is invoked, it is pushed onto the stack, and when the function execution completes, it is popped off. The Call Stack follows the Last In, First Out (LIFO) principle, meaning the most recently added function is the first to be executed.
Microtask Queue: The Microtask Queue holds tasks that are prioritized to execute immediately after the current function execution completes and the Call Stack is empty. Promises and mutation observers are common sources of microtasks.
Macrotask Queue: The Macrotask Queue (often simply called the Task Queue) is where tasks such as setTimeout, setInterval, and I/O operations are placed. These tasks are executed only after the Microtask Queue has been cleared.
2. Interaction and Execution Flow
Order of Operations:
Differences Between Microtask and Macrotask Queues:
Processing Events, Promises, and Asynchronous Functions:
3. Visual Representations
Below are graphical representations of the execution model.
Recommended by LinkedIn
+-----------------+ +-----------------+
| Call Stack | | Microtask Queue |
|-----------------| |-----------------|
| console.log() | | Promise.then() |
| functionOne() | +-----------------+
| main() | +-----------------+
| | | Macrotask Queue|
+-----------------+ |-----------------|
| setTimeout() |
+-----------------+
1. Call Stack empties.
2. Process Microtask Queue: Promise.then().
3. Process Macrotask Queue: setTimeout().
4. Examples
Code Example 1: Synchronous vs Asynchronous Execution
console.log('Start'); // Call Stack executes this first.
setTimeout(() => {
console.log('Macrotask: setTimeout');
}, 0);
Promise.resolve().then(() => {
console.log('Microtask: Promise.then');
});
console.log('End');
Output Explanation:
Output:
Start
End
Microtask: Promise.then
Macrotask: setTimeout
Code Example 2: Nested Microtasks
console.log('Start');
Promise.resolve().then(() => {
console.log('Microtask 1');
Promise.resolve().then(() => {
console.log('Nested Microtask');
});
});
setTimeout(() => {
console.log('Macrotask');
}, 0);
console.log('End');
Output Explanation:
Output:
Start
End
Microtask 1
Nested Microtask
Macrotask
5. Conclusion
The Call Stack, Microtask Queue, and Macrotask Queue form the backbone of JavaScript’s asynchronous execution model. Understanding their interplay ensures better performance and responsiveness: