Event Loop is one of the most important concepts in JavaScript.
JavaScript is a single-threaded language which means it has only one call stack. Therefore, it can only do one task at a time.
This vice is a virtue in disguise. As it increased the simplicity to program in JavaScript.
But what about asynchronous behaviour on the Web. Isn't JavaScript synchronous?
Here event loop comes to play. In most browsers, every tab has a separate event loop to avoid heavy processing to block the entire browser.
Ok, but what the heck is an event loop?
The event loop looks something like that shown in the picture below. It has a call stack, a microtask queue, a task queue and Web APIs also have a role to play.
Such an iteration is called a tick in the Event Loop. Each event is just a function callback.
For example - when your JavaScript program makes an Ajax request to fetch some data from the server, you set up the “response” code in a function (the “callback”), and the JS Engine tells the hosting environment:
“Hey, I’m going to suspend execution for now, but whenever you finish with that network request, and you have some data, please call this function back.”
The browser is then set up to listen for the response from the network, and when it has something to return to you, it will schedule the callback function to be executed by inserting it into the event loop.
And what are these Web APIs?
In essence, they are threads that you can’t access, you can just make calls to them. They are the pieces of the browser in which concurrency kicks in.
How setTimeout() works
setTimeout(() => {}), 0)
takes callback & timer in millisecond as an argument. It sets up a timer. When timer expires, JavaScript environment places callback to task queue.
Call Stack
This is where all the code is executed. It is a LIFO queue(Last In First Out). The event loop continuously checks for the call stack to see if there is a function to run.
Task Queue
Whenever event loops encounter a Web API like setTimeout(() => {}), 0)
, It removes it from Call Stack and then sends the callback function after the timer to the task queue. Once the call stack gets empty, the functions in the task queue are sent to the call stack for executing
Microtask Queue
Whenever event loops encounter a promise in call stack, It sends it to the microtask queue. Once the call stack gets empty, the functions in the microtask queue are sent to the call stack for execution. The Microtask queue has more priority than the Task queue. Therefore, the promise gets executed first then functions from Task Queue are allowed in the call stack.
Example -
console.log('Hi');
setTimeout(function cb1() {
console.log('cb1');
}, 5000);
console.log('Bye');
Let's execute the code snippet and see what happens
- Initially, the call stack, task queue & microtask queue are empty.
- Then
console.log("Hi")
is pushed in the call stack then executed - Then
setTimeout(function cb1() { console.log('cb1'); }, 5000);
is executed & removed from call stack. The browser creates a timer as part of the Web APIs. It is going to handle the countdown for you. -
console.log('Bye')
is added to the Call Stack & executed. - After 5000 ms, the timer completes and it pushes the cb1 callback to the Task Queue.
- Event loop checks if call stack is empty. Finding the event loop empty, it passes the cb1 callback to call stack.
- cb1 is executed.
Conclusion
The event loop is just a guardian who keeps good communication with Call Stack and Callback Queue. It checks if the call stack is free, and then let know the callback queue. Then Callback queue passes the callback function to the Call stack to be executed. When all the callback functions are executed, the call stack is out and the global execution context is free.
Top comments (0)