Skip to main content

Command Palette

Search for a command to run...

Synchronous vs Asynchronous JavaScript

Updated
6 min read
Synchronous vs Asynchronous JavaScript

When someone asks if JavaScript is Synchronous or Asynchronous, people often get confused. The reason is - that it is both in a sense. An accurate answer to this cannot be determined without extra information about the intent behind the question. But what is the meaning of synchronous and asynchronous? And what is JavaScript's connection with these words. Let's explore that in depth.

Synchronous Code

The flow of execution of a program is usually to execute a code line by line. Meaning that if someone does this in a language:

print(1);
print(2);
print(3);

They will expect an out put of :

1
2
3

And not :

2 
1 
3

This is because they know that the code is being executed line by line or more precisely one instruction at a time. Since instructions are given in a sequence , they are executed one by one.

This line by line execution is called as synchronous execution. And a language whose instructions are executed in such a manner is said to have a synchronous nature. 'Core' javascript is synchronous in nature. This is because any code that executes in JavaScript has to be first pushed in the call stack. A call stack works on a single thread.

Thread

A thread can be thought of as a worker that executes instructions given to it. It doesn't switch or pause execution. How many threads we can have depends on our CPU cores. And the more threads we have the more parallel work we can do - because each thread can work independently.

First - to execute the program the main code is pushed into the call stack as the 'Global Execution Context' . If any function is called - that function is pushed over this context. Rest of the code cannot execute because there is already code present in the call stack that needs to be executed. Only when that code has finished execution - can we continue to execute the code of the global execution context. Therefore at a given time only one code can be executed at a time.

Asynchronous Code

So now that we know that synchronous code executes line by line - what is asynchronous code. Code doesn't execute line by line? So for:

print(1); print(2); print(3);

We can get any output. But then we will lose predictability. That is something that should never happen in a programming language. So what happens? And what is Asynchronous?

Suppose you go to a restaurant and order Masala Dosa and Veg Fried Rice. You can just place the order and wait for it to be ready. But internally in the kitchen it won't be like that first your Dosa will be cooked and then the Fried Rice. If that is how they managed the restaurant then it will be shut down pretty soon. Therefore they have multiple chefs. One will prepare the Dosa and the other one will prepare the Fried Rice. This is how they are able to provide practically fast service. So the key here was - the task was delegated to multiple chefs.

Similarly in code - JavaScript has identified segments of code that take time , and designed them to be handed over to different threads which are part of the runtime environment. With this parallelism can be achieved! This method of programming where multiple threads perform different independent tasks simultaneously is called as asynchronous programming.

'Blocking' code and Asynchronous JavaScript

Now if JavaScript is synchronous and code executes via call stack , then why is JavaScript said to work Asynchronously ? This is where we have to move out of 'core' JavaScript a bit and look at the environment of execution.

We know that if somewhere JavaScript is executable then we have 2 things at play :

  1. The JavaScript Engine (V8 / SiderMonkey / JavaScriptCore)

  2. A runtime Environment ( Browser / NodeJs / Bun )

So when we are working with JavaScript in a particular environment , some functionalities are of core JavaScript and others and provided by the runtime environment (like setTimeout or fetch). However some of these environment provided functionalities take more time to run than normal code.

For example:

setTimeout(someFunction,2000);
//or
const data = fetch('url');

These functions mostly take some extra time to execute. If these functions were allowed to run normally they would block the rest of the code from executing and hog the thread all for themselves. This would cause the UI to freeze (in case of browser) or freeze resources (in case of NodeJS). Hence this type of code is called 'blocking' code.

The Solution

Now if our code actually waits for them to return then everything would freeze in the browser , or in NodeJS - not allow us to handle concurrent requests . This is something that is not acceptable because at scale every millisecond is worth money.

JavaScript developers understood this problem- that some of the browser provided APIs take time . Hence they designed those APIs to be executed in a separate thread from the thread pool. (A thread pool is a limited number of threads provided by the runtime environment for Asynchronous Tasks). This is why JavaScript behaves asynchronously. But now we understand that it is not JavaScript that behaves Asynchronously but the complete package of JavaScript and JavaScript runtime environment that bring about this behavior.

So now a code like this:

console.log('one');

setTimeout(()=>{console.log('two');},2000);

console.log('three');

prints:

one
three
(after 2 seconds)
two

This is because our normal 'non blocking' code got executed first without waiting for the 'blocking' code. And once our 'blocking' code (setTimeout) was complete the function was pushed into call stack - printing 'two' on our console.

But naturally, a question arises .If code executes in parallel then how does it combine at the end. After all , the entire code is a single program. If internally it was divided in segments, it needs to be merged too! How is that managed? This is where our event loop comes in. It manages a separate queue and decides when and how tasks will be added to the call stack.

Check out my next article on event loop:-