Photo by Billy Huynh on Unsplash
Event Loop in JavaScript: Understanding Javascript Functionality Behind the Scene!
In the world of web development, mastering asynchronous programming is crucial for building efficient and responsive applications. At the heart of JavaScript's asynchronous nature lies the Event Loop, a fundamental concept that governs how JavaScript handles asynchronous operations. Understanding the Event Loop is essential for every JavaScript developer, as it enables them to write code that behaves predictably and efficiently. In this blog post, we'll delve into the Event Loop in JavaScript, demystifying its workings and exploring its significance in modern web development.
What is the Event Loop?
The Event Loop is a mechanism in JavaScript that allows asynchronous operations to be executed efficiently without blocking the main execution thread. It ensures that tasks are executed in a non-blocking manner, allowing the browser to remain responsive even while performing heavy computations or waiting for I/O operations to complete.
How Does the Event Loop Work?
At its core, the Event Loop continuously checks the execution stack and the task queue. The execution stack contains the stack frames of functions that are currently being executed, while the task queue stores tasks that are ready to be executed. When the execution stack is empty, the Event Loop checks the task queue for pending tasks. If there are tasks in the queue, they are dequeued and executed one by one.
Understanding the Call Stack, Web APIs, and Callback Queue
To grasp the Event Loop fully, it's essential to understand the Call Stack, Web APIs, and Callback Queue.
Call Stack: The Call Stack is a data structure that keeps track of function calls in the order they are invoked. When a function is called, a new stack frame is created and pushed onto the stack. When the function returns, its stack frame is popped off the stack.
Callback Queue: When asynchronous operations are complete or events occur, their corresponding callback functions are placed in the Callback Queue. These callbacks are executed by the Event Loop when the execution stack is empty.
Web APIs: Web APIs are provided by the browser and allow JavaScript to interact with the browser environment, such as making network requests, setting timers, and handling events. Functions that interact with these APIs are offloaded from the main thread and executed asynchronously.
Example 1:
console.log('Start');
setTimeout(() => {
console.log('Inside setTimeout callback');
}, 0);
console.log('End');
In this example, 'Start' and 'End' will be logged to the console first, followed by 'Inside setTimeout callback'. Even though setTimeout() is called with a delay of 0 milliseconds, the callback function is not executed immediately. Instead, it's placed in the Callback Queue and executed by the Event Loop when the stack is empty.
Example 2:
console.log("begins");
setTimeout(() => {
console.log("setTimeout 1");
Promise.resolve().then(() => {
console.log("promise 1");
});
}, 0);
new Promise(function (resolve, reject) {
console.log("promise 2");
setTimeout(function () {
console.log("setTimeout 2");
resolve("resolve 1");
}, 0);
}).then((res) => {
console.log("dot then 1");
setTimeout(() => {
console.log(res);
}, 0);
});
After reading the above code, what do you think will be printed out after executing the code?
The answer is as follows, let us analyze it together.
After the program code is executed, the program will be executed in order, so begin
will be printed first. Then, the setTimeout
will be placed in the macrotask queue.
That is why new Promise
will be executed first. It will print out promise 2
, and then the setTimeout
within the promise will be put into the macrotask queue.
Now, the main thread is empty again, so the event loop will check the macrotask queue, execute the first setTimeout
in the queue, then print setTimeout 1
, and then put the Promise.resolve()
within it to the microtasks queue.
Because the macrotask will only execute the first item each time, we turn to the microtask queue, then we will find that there is a Promise.resolve()
, so promise 1
will be printed. Now, the microtasks queue is empty, so go back and look at the macrotasks queue.
In the macrotasks queue, there is a setTimeout
, so it prints setTimeout 2
. Then since resolve
is called here, it enters .then
and prints out dot then 1
. And setTimeout
will be put in the macrotask queue, because the microtask queue is empty now, setTimeout
in the macrotask queue will be put on the execution stack, and then print console.log(res)
. The value of resolve
is resolve 1
, so resolve 1
is printed at the end.
"begins";
"promise 2";
"setTimeout 1";
"promise 1";
"setTimeout 2";
"dot then 1";
"resolve 1";
Note :
For Further and deeper understanding, Please refer to the below links,
https://latentflip.com/loupe/ , For Live simulation .