Understanding the JavaScript Event Loop

Rajan V
3 min readJun 21, 2024

--

JavaScript is single-threaded, meaning it executes code in a single sequence and cannot perform multiple operations simultaneously. However, it can handle asynchronous operations using the event loop, which is the mechanism responsible for managing the execution of multiple operations over time. The event loop allows JavaScript to perform non-blocking I/O operations, like network requests, timers, and more.

Event Loop Components

Call Stack:

  • The call stack is where the JavaScript engine keeps track of the function calls. Functions are pushed onto the stack when invoked and popped off when they return.

Web APIs:

  • Web APIs are provided by the browser (or Node.js environment) to handle asynchronous operations. These include setTimeout, DOM events, HTTP requests, etc. When an asynchronous operation completes, it sends a callback to the task queue.

Task Queue (Macrotasks):

  • The task queue (or macrotask queue) holds tasks from operations like setTimeout, setInterval, and I/O tasks. These tasks are processed by the event loop one by one.

Microtask Queue:

  • The microtask queue holds tasks from operations like Promise callbacks and MutationObserver callbacks. Microtasks are processed immediately after the currently executing script and before the event loop processes the next macrotask.

Event Loop Mechanism

The event loop constantly checks the call stack and the task queues. Here’s how it works:

1.Execute Synchronous Code:

The JavaScript engine starts by executing all the synchronous code in the current script. It pushes and pops functions on and off the call stack.

2. Process Microtasks:

After the synchronous code, the event loop checks the microtask queue and processes all the microtasks before moving on to the macrotask queue. If new microtasks are added while processing, they are also executed before continuing.

3.Process Macrotasks:

Once the microtask queue is empty, the event loop picks the first task from the macrotask queue and processes it. This task could be a timer callback, an event handler, etc.

4.Repeat:

The event loop repeats this cycle, ensuring that the JavaScript code executes in an orderly manner, managing both synchronous and asynchronous operations effectively.

Code Execution Example

Let’s revisit the provided JavaScript code with the context of the event loop:

console.log('1');
setTimeout(() => {
console.log('2');
Promise.resolve().then(() => {
console.log('3');
});
}, 0);
Promise.resolve().then(() => {
console.log('4');
setTimeout(() => {
console.log('5');
}, 0);
});
console.log('6');

Step-by-Step Execution

  1. Synchronous Code:
  • console.log('1') logs 1 to the console.
  • console.log('6') logs 6 to the console.

Current output:

1  
6

Microtasks Queue:

  • The first Promise.resolve().then adds a microtask to log 4 and schedules another macrotask to log 5.

Macrotasks Queue:

  • The setTimeout schedules a macrotask to log 2 and adds another microtask to log 3.

Microtasks Execution:

  • The microtask logs 4 to the console and schedules a macrotask to log 5.

Current output:

1  
6
4

Macrotasks Execution:

  • The first macrotask logs 2 to the console and schedules a microtask to log 3.

Current output:

1  
6
4
2

Microtasks Execution:

  • The microtask logs 3 to the console.

Current output:

1  
6
4
2
3

Remaining Macrotask Execution:

  • The final macrotask logs 5 to the console.

Final output:

1  
6
4
2
3
5

Conclusion

The JavaScript event loop is essential for handling asynchronous operations, ensuring that tasks are processed in an orderly and efficient manner. By understanding the event loop, developers can predict the execution order of complex asynchronous code, leading to more effective debugging and code optimization.

--

--