DEV Community

Mohamad Harith
Mohamad Harith

Posted on • Updated on

Explain Javascript as a Single Threaded Non-blocking Asynchronous Programming Language Like I'm Five

When I first started to learn Javascript in depth, this is the description of Javascript that I stumbled upon:

A single threaded non-blocking asynchronous programming language.

In this article, I would like to attempt to explain the above description of Javascript.

Based on the description above, if Javascript is single threaded, meaning it could only perform one task at a time, how could it be non-blocking when performing asynchronous tasks - tasks that takes longer time to complete, without blocking the execution of the main thread? Mustn't Javascript be doing multithreading if it were to perform such asynchronous tasks?

Let's look at the example below and see whether Javascript is really single threaded like how it claims to be:

function getData() {
  setTimeout(function print() => {
    console.log("hello");
  }, 1000);
}

function main() {
  getData();
  console.log("world");
}

main();

// output1:
// hello
// world

// OR

// output2:
// world
// hello
Enter fullscreen mode Exit fullscreen mode

Based on the code snippet above, try to guess which output the program would produce - output1 or output2?

Most of us would easily guess it is output2 and yes, it is correct. From an amateur programmer point of view, output2 makes perfect sense, because getData takes 1 second to resolve, hence the program would log world followed by hello once the 1 second has passed. So what is the catch here? Well, the catch is that Javascript is single threaded!

If Javascript is really single threaded, like how it claims to be, it would have produced output1 instead of output2. This is because, for single threaded languages, it would need to wait for the getData to be resolved first and would block the execution of the subsequent lines, hence logging hello followed by world.

But as you can see above, this wasn't the case because calling getData did not block the execution of the subsequent lines (this is what they mean when they say Javascript is non-blocking) and the program logged world first and once getData got resolved after sometime (this is what they mean by asynchronous - something that takes longer time to complete), it then logged hello.

So, is Javascript really single threaded like how it claims to be? The answer is yes. But, how does Javascript achieves this non-blocking asynchronous nature while being single threaded?

You see, although Javascript itself is a single threaded language, Javascript engines such as the V8 engine provides components such as the call stack, callback queue, event loop and makes use of the web APIs provided by the web browser and augments Javascript to create its multithreading illusion.

Image description

Below are the comprehensive definition of these components:

  1. Call Stack - a stack data structure that keeps track of where in the program we are. While the Javascript engine interprets the code, when it runs into a function, it would be put on the stack and when a function is returned, the top of the stack would be popped off.
  2. Web APIs - a set of APIs such as the setTimout, fetchAPI and DOM Event Listeners APIs provided by the browser which would be consumed by the Javascript engine. These APIs would run on a separate thread in the browser. A Javascript callback would be required to be provided in order to call these APIs.
  3. Callback Queue - a queue data structure that keeps track of the callbacks. When any of the calls to the Web API completes, it's callback function would be pushed into the Callback Queue.
  4. Event Loop - an observer that looks at the Call Stack and Callback Queue. Whenever the Call Stack is empty, it would pop the first item from the Callback Queue and pushes it into the Call Stack. This process would run forever in loop.

In regards to the above program, the following is what happens under the hood:

  1. Function call main() gets pushed into the Call Stack.
  2. Function call getData() gets pushed into the Call Stack.
  3. Function call setTimeout() gets pushed into the Call Stack.
  4. A call to the Web API's setTimeout() function is made with print() as its callback and the Web API starts a timer. Once 1 second has passed, the Web API would push the print() callback to the Callback Queue.
  5. Function call setTimeout() returns and it is popped off the Call Stack.
  6. Function call getData() returns and it is popped off the Call Stack.
  7. Function call console.log("world") get pushed into the Call Stack.
  8. Function call console.log("world") prints world and returns.
  9. Function call console.log("world") is popped of the Call Stack.
  10. Function call main()is popped of the Call Stack.
  11. The call stack is now empty, the Event Loop looks at the Callback Queue to see if there are any callbacks present to be pushed into the Call Stack.
  12. If 1 seconds had already passed by now, the print() callback would have been passed to the Callback Queue. The event loop pops the print() callback off the Callback Queue and pushes it into the Call Stack.
  13. Function console.log("hello") get pushed into the Call Stack.
  14. Function console.log("hello") prints hello and returns.
  15. Function console.log("hello") is popped of the Call Stack.
  16. Function print() is popped of the Call Stack.

Below is the visualisation of the process mentioned above and this visualisation can be found here.

Image description

As a conclusion, I think we have made justice that Javascript is a single threaded non-blocking asynchronous programming language. Javascript engines, such as the V8 engine augments Javascript and creates an illusion that it is multithreaded using various components such as the call stack, callback queue, event loop and web APIs.

I would like to end this article with a quiz to test our understanding of Javascript internals, please free to answer them in the comments below.

// What would be the output when main is called?
// Wiil it output output1 or output2?

function main() {
  console.log("1");
  setTimeout(function callback() {
    console.log("2");
  }, 0);
  console.log("3");
}

main();

// output1:
// 1
// 2
// 3

// output2:
// 1
// 3
// 2
Enter fullscreen mode Exit fullscreen mode

Reference:

  1. What the heck is the event loop anyway? | Philip Roberts | JSConf EU

Latest comments (2)

Collapse
 
luthfiaed profile image
Luthfia Ersyana Dianasari

is the answer output2? great article by the way! 😁

Collapse
 
mohamadharith profile image
Mohamad Harith

thank you! and yes the answer is output2.