In this article, we will try to understand how javascript executes asynchronous code and the different concepts associated with it.
Async javascript
Javascript is a single-threaded language at runtime which means only one thing can happen at a time. That is, the JavaScript engine can only process one statement at a time in a single thread. It also means you can’t perform long operations such as network access without blocking the main thread. That’s where asynchronous JavaScript comes into play. Using asynchronous JavaScript (such as callbacks, promises, and async/await), you can perform long network requests without blocking the main thread.
How does asynchronous javascript work?
To understand how async javascript work, we have to understand the concepts like call stack, web APIs, callback queue, microtask queue and event loop.
Call stack
The call stack in JavaScript is also known as the "execution context stack". The JavaScript execution contexts (Global execution context and function execution context) are executed via the JavaScript engine. To manage these execution contexts, the JS engine uses the call stack. So, the JS call stack is a data structure that keeps track of information of the functions being called and executed. Thus, if the user invokes a function for execution, the specified function gets pushed/added in the call stack, and when the user returns from a function, it means the function is popped out from the call stack. Thus, the call stack is a normal stack data structure that follows the stack order principal, i.e., LIFO (Last In First Out).
Web APIs
Web APIs are responsible for filling the callback queue, providing many features such as the ability to make an AJAX request, setTimeout, and DOM events. These APIs allow us to perform tasks that take a certain amount of time to complete, such as sending a network request or setting a timer and the rest of the javascript code is executed without being blocked by the asynchronous task.
Event loop
The Event Loop is a mechanism that manages the execution of asynchronous code in javascript. The Event Loop has one simple job — to monitor the call stack and the callback queue. If the call stack is empty, the event loop will take the first event from the queue and will push it to the call stack, which effectively runs it.
Callback Queue
The callback queue is a list that contains callback functions that are waiting for their execution. When the Web APIs complete the task using the callback functions, it goes to the callback queue. Then the event loop checks the callback queue and call stack and if the call stack is empty, it executes the callbacks one by one.
Job Queue
Not all tasks are of the same priority. Some tasks have higher priority than others. So here comes the job queue in the picture. When Web APIs complete a task using promises, then it goes to the job queue and the event loop checks if there is something in the job queue and the call stack is empty, it pushes the job into the call stack and then the job will be executed.
Example
Now, we will understand all the above mentioned concepts with the help of an example:
function logA() {
console.log("A");
}
function logB() {
setTimeout(() => {
console.log("B");
}, 1000);
}
function logC() {
console.log("C");
}
logA();
logB();
logC();
The expected output of this would be:
A
C
B
Let me explain why:
Step 1: First of all, logA function is called, its execution context is placed in the call stack and the function is executed, A will be printed immediately in the console and the logA function will be popped off.
Step 2: Then, the logB function will be called and its execution context is made in the call stack and then the function is executed. But the Js engine doesn't know how to execute setTimeout, so it will make a web API call because of the setTimeout function which has a timer of one second. So after one second, the anonymous function attached to the setTimeout will be placed in the callback queue.
Step 3: The event loop waits for the call stack to be empty to push anonymous function i.e cb into the call stack. Now the excecution context of logB function is popped off the call stack.
Step 4 : Now the execution context of function logC is created in the call stack and C will be printed in the console.
Step 5: The execution context of logC function will be popped off.
Step 6: The call stack is empty now and event loop will push the anonymous function from callback queue to the call stack.
Step 7: The execution context of callback function is created in the call stack and now the B will be printed in the console.
Step 8: Finally, the execution context of callback function is popped off the call stack.
So this is a detailed explanation of how asynchronous javascript works.
Conclusion
In this article, we discussed different concepts like call stack, web APIs, callback queue and event loop to understand asynchronous javascript. Because Web APIs often provide data asynchronously, learning how to handle the result of asynchronous actions is an essential part of being a JavaScript developer. I hope this article helped you understand the topic.