Asynchronous Programming with JavaScript

ยท

4 min read

Why Asynchronous Programming?

JavaScript is a single-threaded language which means it can execute only one task at a time. For example -

function one(){
      console.log("one");
}
function two(){
      console.log("two");
}
one();   // "one"
two();   //"two"

You see how it runs above two functions one after another. When one function completes its execution then the two function is executed.

But consider a scenario in which you want to execute something which you know will take a long time. If you execute that synchronously, it will block the main thread until its execution is complete. Until then the UI will get stuck in the browser and the user won't be able to do anything. This is the worst user experience and most probably that user will not come again to your website. So how to deal with this?

Simple! Don't execute that task on the main thread. But JavaScript is single-threaded. Right?

Yes, and that's why when we want to execute some time taking the task, we give it to the JavaScript Runtime Environment. This can be either Browser or Node.js. So we delegate those time taking tasks to these runtime environments. These environments provide **Web APIs ** to execute Async Code. For Example - setTimeout(), setInterval(). Let's go deep to find out how all of this is done internally.

Terminologies

Execution Context -

Whenever JavaScript code is executed an execution context is created. Execution context is basically an environment in which a JavaScript code executes. It is of two types -

1. Global Execution Context -

The code which is not written inside any function is executed in the global execution context.

2. Function Execution Context -

A new execution context is created whenever a function is invoked.

Call Stack -

It is used to store the execution contexts getting created while execution. Also, a stack is a Last In First Out Data Structure which means the last execution context pushed inside the stack will be the first to pop from the stack.

Callback Queue/Message Queue/Job Queue -

So when any asynchronous code completes its execution, it is certainly possible that we want something to execute after that asynchronous task has been complete. To do this, a queue is maintained. This queue contains all those after operations that are requested to happen after an asynchronous code execution is complete.

Event Loop

You must be wondering if something is put in a Message Queue/Job Queue/Callback Queue then how it pushed back to call stack to get executed. This is exactly what the event loop does. It keeps checking if there is something in the message queue and if there is then it pops it from the queue and pushes it in the call stack. BUT there is one condition. This only happens when the call stack is empty. Otherwise until and unless the call stack is not empty, the operations inside the message queue will not be executed.

Screenshot 2021-06-15 174352.png

Now lets execute some async code -

setTimeout(function(){
    console.log("This is getting printed after 5 secs");
},5000)

setTimeout() is a Web API that takes a function as the first argument and time as the second argument after which that function will execute. So when the above code will execute following steps will be performed -

  1. setTimeout() will be pushed in the call stack.

  2. When it will execute, it will set 5 secs timer in the background and will get popped from the stack. So right now call stack gets empty.

  3. Now after 5 secs, the anonymous function which is passed as the first argument in setTimeout will be pushed in the message queue.

  4. Now since the event loop keeps checking the message queue, it will find an anonymous function in the queue. Also call stack is empty right now, so the event loop will pop the anonymous function from the queue and will push it in the call stack.

  5. Anonymus function will execute and since it does a console.log() inside, this console.log("This is getting printed after 5 secs") will be pushed on top of the call stack.

  6. At last, this console.log() will execute and print "This is getting printed after 5 secs" and will get popped from the call stack.

  7. Now since there nothing more to execute inside an anonymous function so it will also get popped from the call stack and the call stack gets empty again.

This is how generally any asynchronous code is executed.

I hope you would have learned something new today.

Have a good day. ๐Ÿ™‚

ย