Asynchronous programming is the approach of creating code that could execute in parallel and does not have to wait for an action to complete before moving on to the next action, The ideology behind this is to have actions that are independent of other actions and hence executing them in sequence would be a waste of precious time. Keeping this programming paradigm in mind, Node.Js was created.

What Is NodeJS?

NodeJs is a JavaScript runtime built on Chrome’s V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js’ package ecosystem, npm, is the largest ecosystem of open source libraries in the world. This is the official description given on the website for it, though the description is very clear and to the point, I’ll try to break it down and explain every part of it.

Chrome V8 is is the javascript engine created by the awesome people at google, it can compile javascript codes, it also handles things like memory allocation and garbage collection. More amazingly it is actually an open source project so anyone is free to clone it and understand how it works or even improve it further.(https://github.com/v8/v8)

Event driven programming is a programming methodology in which the execution of the codes depends on certain events like a press of a key, mouse click, mouse movement, etc. Events are not always physical events like the one mentioned in the previous example they could also be something like receiving a network request or a custom event. How an event driven application works is important to understand how node works, in an application designed around such methodology the application is always listening to events, on the trigger of an event it calls the callback of the event(every event has a callback assigned).

Non-blocking I/O model is the asynchronous nature of nodeJs, Asynchronous programs are also known as non-blocking programs, this is because they do not stop the flow of the program when a huge operation needs to take place, people familiar with threads(parallel programming) might be well versed with this type of programming, however nodeJS is single threaded hence it is not truly parallel, we can call it pseudo-parallel as invocation of two actions will never happen at the same time however it is possible for two actions to be executing parallelly.

To understand the flow of asynchronous program let us consider two simple programs.

example with synchronous approach

var fileSystem = require("fs");

console.log("Action Start");

fileSystem.readFileSync("largeFile.csv"); //heavy operation

console.log("The file 'largeFile.csv' has been read");

fileSystem.readFileSync("smallFile.csv"); //lighter operation

console.log("The file 'smallFile.csv' has been read");

console.log("Action End");

Output:

Action start

The file 'largeFile.csv' has been read

The file 'smallFile.csv' has been read

Action End

As this program contains no asynchronous operation it will execute in sequence i.e it will print ‘Action start’ as soon as the program runs, then it won’t print anything for the time it takes to read the large file once it is done reading the file, it prints the acknowledgement of the file, then it read the small file and print the acknowledgement for that.

same example with the asynchronous approach

var fileSystem = require("fs");

console.log("Action Start");

fileSystem.readFileSync("largeFile.csv",function (){

console.log("The file 'largeFile.csv' has been read");

}); //heavy operation

fileSystem.readFileSync("smallFile.csv",function (){

console.log("The file 'smallFile.csv' has been read");

}); //lighter operation

console.log("Action End");

Output:

Action start

Action End

The file 'smallFile.csv' has been read

The file 'largeFile.csv' has been read

As this program contains readFile instead of its synchronous version, the sequence of the output changes, the first statement will be printed instantly as it did in the previous program, however this time instead of waiting for the file to be read completely, the statement after both file reads will execute instantly as well, after this when the files have been read completely the callbacks will be triggered which will print the remaining statements.

In the examples we can also see why the asynchronous approach is better when we have independent actions, Now let us understand how V8 actually executes asynchronous programs, to understand this we must first learn about JS event loop.

The Event Loop

The event loop is the simple programming flow that a JS program uses, we can think of it as a simple 3 part system - Call Stack, API, and the Callback Queue. Call stack is every statement that is read in our JS code, every statement which executes comes into the call stack and then moves out of it when done, The API part is where we are actually making a function asynchronous and the callback queue is where the callbacks of the asynchronous functions are moved when the asynchronous function is completed.

Let us take an example and visualize the event loop for it.

var fileSystem = require("fs");

console.log("Event Started");

function callbackA(){

console.log("Large File Read");

}

function callbackB(){

console.log("Small File Read");

}

fileSystem.readFile("largeFile.csv",callbackA); //heavy operation

fileSystem.readFile("smallFile.csv",callbackB); //lighter operation

console.log("Event Ended");

Schematic user -> web server setup

The first thing you would notice is that the synchronous actions never have to go through the loop completely, they just come to call stack get executed and is available on the output, However, the Asynchronous function are moved to the API stack where they stay until the operation is completed, once their operation is completed they move the callbacks into the callback queue, the callback queue then in order of arrival sends the callbacks to the stack which then executes the callbacks.

Also note the visualization shows that the callback queue waits for completion of reading the large file before sending the callback of the smaller file to the call stack, this is not how it would always execute, the callback queue always keeps sending the callbacks available to the call stack.

How To Async

Up to this point, we have seen what asynchronous programming is and how node handles asynchronous programming, but what if we wanted to make an asynchronous function in JavaScript? Well technically we cannot write an asynchronous program, but we can use the already existing native asynchronous functions available in JavaScript and use them to make our function behave asynchronously.

Let us consider an example

var value = 0;

function syncFunction(){

value = 1;

}

syncFunction();

console.log(value);

output:

1

Now let us make the same function’s asynchronous version

var value = 0;

function syncFunction(){

value = 1;

}

function asyncFunction(){

setTimeout(syncFunction,0);

}

asyncFunction();

console.log(value);

output:

0

Yes, It is as simple as this to make a function work asynchronously, let’s understand what happened in both the outputs, in the first example’s output the syncFunction gets called and goes to call stack the call stack then executes the statements inside the function only after this it reaches the console.log and by now the function has already changed the value of the variable hence why the output is the new value. In the second Output the the asyncFunction called which goes to the call stack and creates a setTimeout event which is an async function in nativeJS we set the callback of the function to our original function and give the timeout at 0, even though the timeout is 0 the timeout event always goes to the API stack of the event loop and instantly(timeout = 0) sends the callback to callback queue, the call stack get the console.log before getting the callback hence the original value of the variable is printed, after this the callback is executed and value of variable is changed.

The async approach gives you the freedom to run different actions independently without blocking any action, Hence it should be used for such programs, asynchronous programming in node does not reduce your overall time taken to execute all actions as it is single threaded, so before making your functions asynchronous have a clear idea of the impact and necessity.