1. 程式人生 > >JavaScript is Synchronous and Single Threaded. (Unfolding the Async Behaviour)

JavaScript is Synchronous and Single Threaded. (Unfolding the Async Behaviour)

How to understand order of execution of any code in JavaScript.

Now as we know the basics of how to understand what is going to be synchronous and what is going to be asynchronous let’s look at this code and take a deep dive into JS to understand the execution order of this code.

In order to guess the output you will need the following rules that JS engine uses.

  1. JS engine will run all the code in the global scope first.
  2. In order to run async functions the call stack must be empty
  3. Functions to be executed in the micro task queue are executed first.
  4. Functions in the callback queues are executed after callback queue.

Don’t sweat it if you don’t understand these rules we will take a look at it one by one.

Code in Global Scope: It is the code that you have written in the entry point of your file in the global scope.

Callback queue: It is a queue in which callbacks given to setTimeout or setInterval are put for the event loop to execute.

Microtask queue or Job Queue: This is a much newer queue. Previously all the functions that were to be called after resolving a network requests were put in the callback queue but now these callbacks are put into the micro task queue or the Job queue.

Now let’s execute the code line by line.

function blockThreadFor(numberMillis) {     var now = new Date();     var exitTime = now.getTime() + numberMillis;     while (true) {         now = new Date();         if (now.getTime() > exitTime)             return;     } }
function printData(data){  console.log(data.title)};
function printHello(){console.log("Hello");}
setTimeout(printHello,0);
futureData.then((response)=>{  return response.json();}).then(printData)
blockThreadFor(1500);
console.log("Hi");

Lets begin.

Function blockThreadFor simply blocks our main thread for some amount of time that we give to it.

Function printData prints the data that we give to it.

Function printHello prints “Hello”.

On the next line we start executing the function in the global scope.

We execute a broswer feature function called setTimeout and hands it printHello function to call after 0ms. As we know setTimeout is async in nature so after 0ms it will put the function printHello inside the Callback queue so that later when the condition meets it will be picked by the Event Loop and put on to the call stack to be executed.

So, will the printHello function run just after calling it? The answer is no, because according to the rules we have not executed all the code in the global scope so it will not be picked by the event loop.

On to the next line we simply make a get request and fetch some data and then chain a then function to convert the response to JSON and then call function printData that will print data for us fetched from the API. Fetch is again a broswer feature. We call it and move to the next line.

On to the next line we block the thread for 1500 ms. Meanwhile the response from the API comes back after 100 ms, but as we have blocked the thread for 1500 ms it will not be printed out.

After 1501 ms the thread will be unblocked and the data that we have fetched will be passed on to the function printData and the printData function will be put into the micro task queue to be picked up by the Event Loop.

So now will the printData function be executed? The answer is no. because still we have some global code to run and as per by the rule we cannot execute function from microtask queue if we have not executed all the code in our global scope.

Now we move to the last line of the code and we print “Hi” on the console.

After that event loop will figure out that all the code in the global scope has been executed so it’s time to check if we have any function in the microtask queue to be executed.

It will find out the printData function. So printData will be put on to the call stack and executed.

After the printData function is executed it will again check if there is any more code inside the micro task queue. As the micro task queue is empty it will move on to the callback queue and execute the printHello function which will console “hello”.

So the correct order of the console would be:

Hi
delectus aut autem
Hello

How surprising it is that the function that we expected to execute in 0 ms was executed almost after 1500 ms, but by simply following the rules we were able to figure out the execution order of our code.

I hope that I have helped you to understand how and why Javascript is Synchronous and Single Threaded.