DEV Community

Cover image for JavaScript: Mastering Asynchrony in a Single Thread
Jaswant Vaddi
Jaswant Vaddi

Posted on

JavaScript: Mastering Asynchrony in a Single Thread

Before we delve into asynchronous JavaScript, let’s first discuss how the JavaScript compiler performs operations.

JavaScript is often referred to as a single-threaded language, meaning it cannot delegate work across multiple threads. Instead, it must execute each operation one by one in a single thread.

This single thread operates like an array. It contains a set of operations to perform, and the JavaScript engine uses push and pop operations to add or remove functions from the stack.

For example:

function consoleLog(){
    console.log("testing")
}
function firstFunction(){
    consoleLog()
}
firstFunction();
Enter fullscreen mode Exit fullscreen mode

In this case, the JavaScript engine, which is always checking for functions to run, initially adds firstFunction to the stack.

Then, it sees that we are calling the consoleLog function. Before completing this function, it adds consoleLog to the top of the stack for execution.

Next, it encounters the console.log() function, which it then adds to the top of the stack. After executing console.log(), it pops this function from the stack. Since there are no remaining parts of the consoleLog function, it pops consoleLog from the stack. Finally, it pops firstFunction from the stack.

Now, let’s talk about asynchronous JavaScript.

An asynchronous function is one that cannot be executed completely and return a value directly because some task within it takes a significant amount of time.

A prime example of asynchronous functions are API calls. These calls connect with servers, which then connect with the required resources and return that resource. This process usually takes more time than we might expect.

Imagine you are running a function, and then there is an API call to get some data from a server. If this call is not asynchronous, your code is forced to wait for the entire duration of the call without doing anything else. Then, it must complete the rest of the function. This can take a lot of time.

So, what does JavaScript do for these asynchronous functions?

These functions are usually browser functions, so the JavaScript engine sends these functions directly to the browser to perform these actions while it continues as usual with the rest of the code.

The browser performs the asynchronous function completely and sends a message to the task queue indicating that this call is completed and provides the return value.

The JavaScript engine is always on the lookout for any function to be performed and to be added to the stack.

For instance, let’s say we added a click event to an HTML button element where this event triggers a function. As soon as we click, the engine knows to perform the click event function and adds that to the stack. The engine is constantly on the lookout for functions to be performed and, once it sees that the stack is empty, it also checks the task queue sent by the browser to see if there is any function to perform.

The engine performs all the functions that are in the stack and then performs the functions given by the browser queue. A great example to observe this phenomenon is this code:

console.log("a")
setTimeout(()=> {console.log("b")},0)
console.log("c")
Enter fullscreen mode Exit fullscreen mode

You can try to run this code and see the order in which “a”, “b”, and “c” are logged to the console.

Here is a small explanation for it:
When we run this code, the first function to go to the stack is console.log("a"), which gets executed and logs “a” to the console.
The second line added to the stack is the setTimeout function. Once this browser API function is triggered, it sends the contents in it to the browser to deal with directly and removes this call from the stack.

The browser immediately returns a message to the task queue saying that you have to perform console.log("b").

But our JavaScript engine will first check if there is any function which is required to be added to the stack before checking the queue. It sees we need to perform console.log("c"), and it doesn’t know there is a message in the queue yet.

Once it logs “c” to the console, it reads the task queue message and logs “b” to the console.

This is my basic understanding and explanation of what asynchronous is and how JavaScript manages it in a single thread.

If there are some more good examples which you think of are know, which showcases asynchronous of javascript please share them

Top comments (0)