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?
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
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
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.
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
Let us consider an example
Now let us make the same function’s asynchronous version
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.