Demystifying the JavaScript Event Loop

Demystifying the JavaScript Event Loop

A Comprehensive Guide to Asynchronous Execution in Javascript

Javascript is a single-threaded language, this means that it can only execute one task at a time. But still, it manages to do multiple tasks concurrently. It gives the illusion of multi-threading through the use of a few sophisticated data structures. To achieve this, the Javascript engine has a vital component called Event Loop. We will be going to understand what Event Loop is and how it handles the async task without blocking the main thread.

Note- To better understand this topic, please read about How Javascript code is executed.

What Is Event Loop?

The Event Loop is a mechanism in Javascript that enables the execution of non-blocking asynchronous operations. It allows Javascript to handle tasks such as fetching data from a server, making HTTP requests, and handling user events without blocking the main thread.

According to MDN Doc, It is a runtime model which executes the code, collects and processes events, and executes queued sub-tasks. Understanding how the Event Loop works is essential for writing efficient and performant code.

To better understand the Event Loop, let's list down the components used in the execution of async code -

  1. Call Stack: JavaScript uses a Call Stack, which keeps track of the currently executing functions (Execution Context). When a function is called, it's added to the stack, and when it returns, it's removed from the stack.

  2. Web APIs: Web APIs are provided by the browser or the JavaScript runtime environment and offer functionalities like DOM manipulation, timers (setTimeout, setInterval), XMLHttpRequest, and more. These APIs handle time-consuming tasks asynchronously.JavaScript interacts with Web APIs, such as the DOM API, XMLHttpRequest, or setTimeout, which provide functionalities outside the JavaScript engine.

  3. Task Queue: The Task Queue (also known as the Callback Queue) holds tasks that are ready to be processed by the Event Loop. These tasks are enqueued when their associated asynchronous operations are complete. Asynchronous operations, such as timers, user events, and network requests, are handled by Web APIs. Once these operations are complete, they are placed in the Task Queue.

  4. Event Loop: The Event Loop continuously checks two things: the Call Stack and the Task Queue. If the Call Stack is empty, it takes the first task from the Task Queue and pushes it to the Call Stack for execution.

Understand Event Loop With Code Examples

console.log('Start');

setTimeout(function() {
  console.log('Inside setTimeout');
}, 0);

console.log('End');

Here, we have 3 console logs statements. But one of the console logs is defined inside the setTimeout web API. This web API will set the timer to the value that is set to the setTimeout (here we have given 0ms) and once the time is completed the setTimeout web API will send the callback to the Task Queue. Now, this will stay there until the mail thread gets released, that is, the Execution Stack gets empty.

The point to note here is that even if the time is set as 0ms in the setTimeout, it will execute at the last. This is because the setTimeout is an async task with a timer attached to it and has to go into the queue and then wait until the main thread is idle. This timer can be 0 ms or 10000 ms no matter what, it will still get registered into the task queue. The following visual diagram explains this clearly-

Now its more clear, right? So, this is how the async tasks work. Note that the time attached to setTimeout is minimal, that is the code will not run at least for the set time. But it will only execute after the main thread is released. Imagine you have a setTimeout with 1000ms but the main thread took 2000ms due to the execution of some complex operation. In this situation the registered setTimeout can only be executed after 2000ms and not immediately after 1000ms!

let's dive into the next example. We will be using the XMLHttpRequest

console.log('Start');

var request = new XMLHttpRequest();
request.open('GET', 'https://api.example.com/data', true);
request.onreadystatechange = function() {
  if (request.readyState === 4 && request.status === 200) {
    console.log('Data received:', request.responseText);
  }
};
request.send();

console.log('End');

I hope from the previous example you have decoded how the above code will work. Yes, the Http async request will be handled by the XMLHttpRequest Web API. It will be processed and sent into the Task Queue. The Event Loop will wait until the main thread is idle and then Dqueue the task inside the Task Queue and put it into the Execution Stack to be executed by the main thread. By this explanation, we can say that the Output will be -

Start
End
Data received: xyz // xyz is any response that API has sent

Conclusion

Understanding the JavaScript Event Loop is essential for writing efficient and responsive JavaScript code. By grasping its inner workings and the role of components like the Call Stack, Web APIs, Task Queue, and Event Loop, you can confidently handle asynchronous tasks and build performant web applications. Armed with this knowledge, you're well-equipped to tackle complex scenarios and make the most of JavaScript's asynchronous nature.

Did you find this article valuable?

Support Code Craft - Fun With Javascript by becoming a sponsor. Any amount is appreciated!