Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / Node.js

JavaScript: The Synchronous Explanation of Asynchronous Programming.

4.95/5 (17 votes)
9 Apr 2016CPOL7 min read 41.9K  
A boring talk about What’s really going on at runtime...

If you've ever asked someday about JavaScript definition… you would get some answer like this:

JavaScript is a Single-threaded, non-Blocking, Asynchronous, Concurrent language!!

Really!,.. Nice!!

Concurrency, Asynchroniztion, Threading, Parallel Programming and a lot of these stuff here… it’s a mess of terms. Although you can easily use one of these terms to explain your idea, it’s also easy to get lost using the right term at the right place, Even experienced developers could miss accuracy choosing the correct word. And what i’m trying to do here is to go more deeply to get better understanding for the difference between these terms... focusing on JavaScript Asynchronous programming.

 

Before Asynchronization… What’s Synchronous code at first?!!

If you have ever written any (Hello World) program with any popular programming language like ( C, Java, C#, Python), This is a synchronous code, which in code is executed line by line in order they are wrote.

code:

JavaScript
Console.log('First Line');
Console.log('Second Line');
Console.log('Third Line');

Output:

First Line
Second Line
Third Line

Yes, you get this result as expected… this is synchronous code.

But before moving forward to asynchronous code, let’s go more in details about what happened really at JavaScript runtime with these lines.

JavaScript Runtime Engine:

From code execution view, We are focusing on one important component of any JavaScript engine (ex: V8, Google’s open source JavaScript engine that is used for Chrome and Chromium projects) which is Call Stack. in simple words, Call Stack is a Stack data structure where V8 stores information about functions that Are currently executed to keep track of the execution flow of the code.

Let’s analyze code like this:

JavaScript
function sayHello(name){
    console.log('Hello, ' + name);
}

function greeting(name){
    return sayHello(name);
}

greeting ('Adam');

  1. Initially, JavaScript runtime pushes a stack frame (let's say main) which represents the script itself or the current block of code.
  2. Declaration of sayHello function, nothing really executed here.
  3. Declaration of greeting function.
  4. By running line 9, JavaScript runtime pushes greeting address at the top of the stack to be executed.
  5. Inside greeting we are calling sayHello function, that means JavaScript has to push sayHello address also to the Call Stack.
  6. Again, Inside sayHello function, JavaScript runtime found calling of console.log function, so it pushes it also to the Call Stack to be run.
  7. After console.log function return, JavaScript runtime pull the stack frame of console.log and move back to the previous address at the Call Stack which is sayHello.
  8. JavaScript runtime finish executing sayHello function and pulls its stack frame from the Call Stack.
  9. pulling the stack frame of greeting.
  10. pulling the stack frame of main.

 

Now, What about Asynchronous code?!, And Why?!

With simple lines like the previous example we can’t find any problem executing this code, the program will run and finish its job smoothly, But what if we have some slow/blocking lines of code?!

Operations like accessing files or database or reading from network are considered very slow, and because of the nature of JavaScript running inside browsers, slow operation (ex: http request) could freeze your web page, so it’s considered a blocking code.

And here become the Asynchronous part. Because JavaScript runs inside Browsers, it must not executing any blocking code, it shouldn’t wait and freeze the web page otherwise users could get a terrible experience trying to browse even simple web pages. So, JavaScript is non-blocking by design and this means it wouldn’t freeze the execution and wait for blocking line of code, instead of this it uses Events and Asynchronous Callbacks techniques.

Events & Asynchronous Callbacks

At this approach, Asynchronous Callbacks provide a solution to avoid blocking code. And the Callback is a function which is registered to be executed when an event occurred, JavaScript will not wait for the blocking code to be finished, rather than this, it will continue executing the next lines and get back again to the callback when the event is fired.

A fake callback would look like:

JavaScript
httpRequest('http://www.google.com/',function myCallBack(){
    console.log('Hey!!');
});  

And this means that after finishing the httpRequest (blocking code), myCallBack function would be executed (callback).

Simple?… OK!?

OK, but now I can see JavaScript can do more than one thing at the same time, it can execute the main thread code and also handle events as well at the same time. Isn’t this kind of Concurrency or something?! Aren’t you said JavaScript is single-threaded and it can do just one thing at a time?!!

One step deeper...

Well, before answering this, it’s time again to get another step deeper into JavaScript environment. And let me introduce new friends to you… please welcome Event-Loop, Message Queue and WebAPI.

If we imagine JavaScript runtime environment, it would be something like this:


 

-WebAPI: it’s the part of the browser that is responsible on the external APIs, DOM APIs and most of blocking IO code like accessing files, network requests or even Timers (setTimeout). It’s job is to fetch back the registered event callback when the browser fire a specific event.

-Message Queue: it’s a simple queue (FIFO) where callbacks from WebAPI come and are stored in order.

-Event Loop: its job is watching the Call Stack, if empty, it pushes the next task at Message Queue into the Call Stack to be executed.

May be this is new for you, Blocking actions like accessing files or network is not a part of JavaScript runtime (V8) itself, even setTimeout, it comes from the hosting environment which is the web browser (or NodeJS), Browser is much more than JavaScript runtime engine.

For code like this :

JavaScript
console.log('first');

setTimeout(function foo(){
    console.log('second');
}, 1000);

console.log('third');

Output:

JavaScript
first
third
second

This happens as we registered function foo to be run after 1000ms. so the runtime runs the first line , then the third line and after 1000ms it back again to execute setTimeout callback and here is what is going at Call Stack and Message Queue.

In setTimeout case, WebAPI setups a timer with interval 1000ms, and waiting for this period to be triggered. Once it’s triggered, WebAPI enqueue the timer Callback function foo into the Message Queue.

Message Queue is a place where Callbacks from events are stored in order and get ready to be executed. And here comes the part of Event loop.

Event loop keeps watching the Call Stack and when Call Stack is empty Event loop pushes the top task at Message Queue into the Call Stack to be executed.

We can simulate this process by this:


 

  1. the initial stack frame to start executing the code.
  2. JavaScript runtime pushes console.log('first') to the Call Stack to be executed, and we got "first" at the output.
  3. Calling setTimeout to setup a timer with callback function foo and interval 3000ms
  4. WebAPI creates a this timer and waiting for 3000ms.
  5. JavaScript continue running the code and pull the stack frame of setTimeout
  6. JavaScript moves to the next line and pushes  console.log("third") to the Call Stack and we got "third" as output.
  7. JavaScript pull the top stack frame.
  8. JavaScript pull the main stack frame.
  9. After 3000ms, and Timer event is fired.
  10. WebAPI enqueue the timer callback foo to the Message queue to get ready for execution.
  11. Event loop checks the Call Stack, and if empty, it pushes foo function into the Call Stack.
  12. executing the body of foo function, console.log('second').
  13. pulling off console.log('second') from the Call Stack
  14. pulling off foo stack frame.  

And this is the way how JavaScript can handle Concurrency with Single-Threaded non-Blocking design...

Please note:

Event loop pushes a new task into Call Stack only when the Call Stack is empty, setting setTimeout(function(){}, 0) -(aka Zero-delay case)- doesn’t mean it will fire immediately, it would be executed when it’s the next at Message Queue AND the Call Stack is empty, also setTimeout(function(){}, 1000) does not guarantee to be executed exactly after 1000ms , but for sure it guarantees not to be executed before this.

 

Conclusion:

Yes, JavaScript is single-threaded by itself, it just can do one thing at a time, and also it’s a non-blocking by design, and it handles Concurrency via Event loop & Asynchronous Callbacks by the help of the browser or the hosting environment.

 

References :

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)