The secret behind JavaScript’s asynchronous nature

Vimala Sirvi
Globant
Published in
5 min readJul 4, 2022

While you learn JavaScript you often hear folks using words like “single-threaded”, “blocking”, and “asynchronous callback”. If at all you are like me, wherein you nod and agree, as if everything is so obvious, even though you hardly know how those terms really work; and yet are curious entities like me trying to find out how JavaScript really works, then lets deep dive!

What is JavaScript?

Single-threaded, non-blocking, asynchronous programming language

Ahh, Single-threaded !!

Which means:

One thread == One call stack == One thing at a time

Let’s visualize how the call stack executes program statements one at a time below:

Fig 1 Single Threaded

Refer to Fig 1: We can see that there are a few function definitions and finally the engine gets to the greet() function call.

  1. We invoke the greet() function
  2. It is pushed onto the call stack
  3. Prints out “Hello”
  4. The greet() method gets popped off
  5. Again the engine encounters new invocation i.e. greetWorld() function
  6. It is pushed onto the call stack
  7. Prints out “Hello World”
  8. The greetWorld() method gets popped off

You might be wondering what is The call stack in the above diagram.

It’s a data structure that keeps track of where in the program we are. If we step into a function then the function is pushed onto the stack and if we return from a function then we pop off the top of the stack.

Wondering where do we find this call stack?

It resides in the JavaScript engine like the Chrome V8 engine. Refer to Fig 2 below:

Fig 2 The JavaScript Runtime (The Chrome V8 engine)

Now we saw how JavaScript is single-threaded and you might be thinking “YES” JS works with the call stack in place. But what if our code takes some time to execute?

What do we exactly call the code which takes time/is slow?

Ahh Blocking !!

Which means:

Things that are slow or take a long time to execute refers to the blocking code.

Problem statement: Imagine we want to subscribe to a channel on YouTube. What if subscribing to a channel took more than x amount of time?

Fig 3 Blocking

The problem encountered: Browsers !!

Refer to Fig 3: The problem in the above scenario is that after we click on the subscribe button our entire screen/browser was stuck until the subscription request was completed.

What’s the solution?

Asynchronous callbacks.

Ahh, Asynchronous callbacks !!

Which means:

We run some code and give it a callback which would be executed at a later point in time. Let’s visualize that using the call stack below:

Fig 4 Asynchronous callback

Refer to Fig 4: On running the above snippet of code we can see that:

  1. 1ˢᵗ console.log() statement would be pushed onto the call stack
  2. Prints out 1
  3. The console.log(1) gets popped off
  4. Similarly, the 2ⁿᵈ console.log() statement is executed
  5. Then the setTimeout function call is pushed onto the call stack to print 3 which would be executed in a minimum of 2 seconds. Hence somehow the setTimeout function disappears !!
  6. Then console.log(4) would be pushed on the call stack
  7. Prints out 4
  8. The console.log(4) gets popped off
  9. A few seconds later magically console.log(3) appears on the call stack and prints out the 3

How did that happen?

The secret behind JavaScript’s asynchronous nature: Event loop !!

You now might be thinking that JavaScript is a single-threaded programming language but not really !!

So JavaScript runtime(The Chrome V8 engine) executes one thing at a time. It can’t make a network request/can’t do a setTimeout while other code is being executed.

So how can we make network requests or how can we execute setTimeout while some other code is being executed?

Because the browser itself has many more things than just the JavaScript runtime(The Chrome V8 engine). Let’s take a look at the below diagram to find out what are those other things.

Fig 5 The bigger picture: Event Loop

Let’s retake a look at the asynchronous callback example’s execution to understand what are the other components: Web/C++ APIs, Task queue, Event loop

Fig 5 Asynchronous callback with the event loop

Refer to Fig 5: On running the above snippet of code we can see that:

  1. The 1ˢᵗ console.log(1) statement is pushed onto the call stack
  2. Prints out 1
  3. The console.log(1) gets popped off
  4. Similarly, the 2ⁿᵈ console.log() statement is executed
  5. Now when setTimeout is pushed onto the stack it is executed outside the call stack i.e. it is executed by the browser’s Web APIs. So the browser kicks off the timer for us and now it will handle its execution. Since the setTimeout’s execution isn’t complete we pop it off from the stack.
  6. We continue executing the snippet for a console.log(4) in a similar fashion as for console.log(1) & console.log(2)
  7. Once the Web API completes the execution of the setTimeout statement it pushes the result onto the task queue. Finally, we get to the “Event loop”. The event loop is like “Hey finally I have a task. Let me take a look at the stack if it is empty. Oh yes, it is! Hence let me push the 1ˢᵗ thing from the task queue to the call stack i.e. the callback”.
  8. Then the result from the callback is printed onto the console i.e. the number 3 and popped off the call stack.

Conclusion

We have learned what the words like “single-threaded”, “blocking”, and “asynchronous callback” mean and event loop which is a constantly running process that monitors the task between the call stack and the queue to achieve the asynchronous nature of JS.

Hope this makes you a little bit more comfortable with the concept of the event loop.

This article is heavily influenced by Philip Roberts’s talk on JS Event Loop. Thank you Philip Roberts for the video, it helped me understand JavaScript much better.

--

--