In this blog I've provided a thorough explanation with images and a clearly described examples.
JavaScript is a single threaded language with one call stack and it can do only one thing at a time, & this Call stack is present in JavaScript engine & all the code of JavaScript is executed inside the call stack.
The call stack is used by JavaScript to keep track of multiple function calls. It is like a real stack in data structures where data can be pushed and popped and follows the Last In First Out (LIFO) principle
The main job of the call stack is to execute all the code that comes inside it & it doesn't wait for anything.
So, as stated above JavaScript call stack executes code without waiting for anything , so what if we need to wait for some function ? How will things execute in that case?
How JavaScript perform async task?
Now, let’s understand what is the scene behind browser.
Inside browser we have JavaScript engine inside which we have our call stack.
Browser or Web APIs are built into your web browser, and are able to expose data from the browser and surrounding computer environment and do useful complex things with it. They are not part of the JavaScript language itself, rather they are built on top of the core JavaScript language, providing you with extra superpowers to use in your JavaScript code.
Some of Web APIs are - setTimeout(),DOM APIs, fetch(),localStorage,console.log(),location
All these are not JavaScript instead they are part of browser which it give access so as to use it inside our call stack because of global object called window .So browser give JavaScript to use these Web APIs inside JavaScript engine with the help of global object window.
NOTE-Although we don’t write window.console.log() always because its a global object and can be accessed directly.
Now lets understand how setTimeout() works behind the scene in browser.
console.log("hello");
setTimeout(function callbck(){
console.log("your 5 second is over");
},5000);
console.log("Bye");
Hello
Bye
your 5 second is over
Here, we can see setTimeout() function in call Stack
Let's see how this code is executed line by line.
JavaScript code executes line by line so “console.log("hello")” will call consol.log web API and print “Hello” in console then,
as soon as it encounter setTimeout() it will execute after the specified time and till then further code line will execute that is it will print “Bye” in console
when the time is over of setTimeout() it will go to callback queue and as soon as event loop detect something is waiting in callback queue, it will send it to call stack to execute the code & prints “your 5 second is over” in console.
Console.log is web API which is called every time whenever required.
Before moving forward let's understand what is Callback Queue, Event Loop, Microtask Queue
Callback Queue: After the timer gets expired, the callback function is put inside the Callback Queue, and the Event Loop checks if the Call Stack is empty and if empty, pushes the callback function from Callback Queue to Call Stack and the callback function gets removed from the Callback Queue. Then the Call Stack creates an Execution Context and executes it.
Event Loop :Event loop is an endless loop, which waits for tasks, executes them and then sleeps until it receives more tasks.
The event loop executes tasks from the event queue only when the call stack is empty i.e. there is no ongoing task. The event loop allows us to use callbacks and promises.
Microtask Queue: Microtask Queue is like the Callback Queue, but Microtask Queue has higher priority. All the callback functions coming through Promises and Mutation Observer will go inside the Microtask Queue. For example, in the case of .fetch(), the callback function gets to the Microtask Queue. Promise handling always has higher priority so the JavaScript engine executes all the tasks from Microtask Queue and then moves to the Callback Queue.
Similar to setTimeout() event listeners also which takes callback function when it encounters click/keypress(etc) then it is pushed to call stack from callback queue to execute the code.
console.log("hello");
document.getElementById("btn").addEventListener("click",function cb(){
console.log("callback");
})
console.log("Bye");
Output in console will be :
Hello
Bye
Callback (if button encounters click/keypress..)
But, if we consider fetch, things work bit differently
Fetch function returns a promise and we have to pass a callback function which will be executed once the promise is resolved.
Let's understand how this code will be executed.
console.log("start");
setTimeout(function callback1(){
console.log("will execute after 5 second");
},5000);
fetch(https://api.netflix.com).then(function callback2(){
console.log("fetching data from api");
})
console.log("end");
For the 1st line of code ,it will call console.log from web API and print “start” in the console.
Since setTimeout is to be executed after 5 seconds so it will register this call in the web API,after 5sec ,this call back will go to callback queue waiting for event loop to call this to call stack for it to be executed .
Meanwhile, fetch() will also register call in webApi and as soon as it gets data from API it will go to micro task queue waiting for event loop to call this to call stack for execution.
Here, fetch will execute faster than setTimeout.
Now the question comes what will happen if we have task in both micro task queue and call back queue(Task queue)
Since microtask queue has higher priority so first all the task of micro task queue will be completed then callback queue.
Conclusion:
JavaScript language is single-threaded and the asynchronous behaviour is not part of the JavaScript language itself, rather they are built on top of the core JavaScript language in the browser (or the programming environment) and accessed through the browser APIs(Web APIs).
If you have any questions, leave a comment and I'll do my best to respond.
Give this article a like if you found it helpful and follow me for more articles like this.
Top comments (2)
Very good explanation of a really important subject - great job. This knowledge is absolutely essential to mastering JavaScript. I have been asked questions related to this subject in several job interviews.
“Thank you Dave! I really appreciate you taking the time to express that.”