Javascript is a synchronous and single threaded programming language which means all codes are executed in sequence and not in parallel.Though, this single threaded or synchronous approach avoids the burden of concurrency handling, on the other hand, it could be time consuming in case of any long running I/O operations which blocks the main thread such as querying large data from DB or accessing the filesystem or fetching large data over the internet using http requests and so on.
So, an asynchrous approach is required to process these long running operations without blocking the main thread.

This article explains about the asynchronous javascript using callbacks, promises and async/await.
This concepts could be little confusing for any javascript beginner who would end up searching different articles and online sources. So, I thought of putting these together in this article.

Target audience : Javascript beginner to intermediate level.(Make sure you are already familiar with anonymous function , arrow function, arrays and  objects)

Synchronous Vs Asynchronous

Before getting in to the subject, let us first understand what synchronous and asynchronous are.Let us consider Restaurant order system as a metaphor where the waiter takes order from the customers and serves them once the order is ready in the kitchen.

Here, Method1 is synchronous where each step is executed in sequence.In this case, the waiter has to wait for the order to be complete and only then take request from next tables.
This is time consuming and not an efficient method where there is high chance of losing the customers.

Method2 is asynchronous approach where the waiter doesn’t have to wait until the Table1 order is prepared in the kitchen but can proceed with taking order from the next table.Once the order is ready, Waiter will be left with a message and he can serve the order to the respective table.This is most efficient way where multiple customers can be served concurrently.

How Asynchronous is achieved in javascript ?

You might wonder, how is it possible to achieve asynchronous approach using javascript which is a single threaded programming language.Here is the brief explanation,

The Javascript code gets pushed to the call stack and gets executed one by one as the interpreter reads the program and eventually gets popped out once the execution is done. If there is any asynchronous statement like setTimeout, promise, click event or ajax(),or anytime consuming asynchronous request, the code is removed from the main stack and forwarded to Event table which is responsible for moving the asynchronous code to callback/event queue after specified time or once the response is received.
Event loops keep monitoring the message queue and the call stack and pushes the dependent or callback function from the message queue to the call stack (for the execution )if the stack is empty.
Job Queue is introduced in ES6 which is used by promises and holds higher priority than the message queue and hence the promise jobs in the job queue are always executed prior to the callbacks in the message queue.

Here, call stack alone is part of javascript engine whereas the WEB API’s, message/job queue and the event loop are part of browser’s JavaScript runtime environment or Nodejs JavaScript runtime environment respectively.

Callback

A callback is a function that gets executed after a task/function has finished executing and hence the name . This callback function is passed as an argument to another function.
There are built in asynchronous functions that takes callback function as an argument. setTimeout() is one among, that takes callback function as an argument which gets evaluated after a specified number of milliseconds.

Back to our restaurant example, assume prepareItems is a request that takes 1000ms for completion after which the item has to be served to the table1.
I am using setTimeout function to simulate this 1000ms delay.


 

Output:

Here, we can witness the power of asynchronous javascript using callback function. prepareItems(‘Table1’) is called before the last 2 statements which in turn makes an asynchronous function setTimeout() which gets executed outside the javascript without unblocking the main thread that could execute the rest of the code. Once the specified interval 1000ms is reached , callback function  is executed which prints the statement ‘Serve items to Table1’ .

In this example , we used the in-built asynchronous function setTimeout() which takes callback function as an argument. In the next example , let us see how to define our own function that takes callback function as an argument.

Forget about the table2 and only consider table1 in this example. Here, the waiter place the Order in the kitchen and gets the Item to serve to the table.

Here, the getItems() call is made only after placeOrder() call which adds veg rice to the Items. So, we expect the output to be,
Expected output:
But the Veg rice never get printed. This is because placeOrder() takes 2000ms to execute whereas the getItems() takes only 1000ms to execute. so, even though getItems() is called after the placeOrder(), the newly added item is never printed.
Actual Output:
How to achieve this using callback function
getItems()  has to be executed only after the placeOrder() is complete. To achieve this , getItems() has to be passed as a callback function to placeOrder(),
Output:
Here the items gets successfully printed because the getItems() is passed as a callback function to placeOrder() function and getItems() is called only after the item is pushed to the Items object.
Callback hell:
If task2 is the only dependent task on task1, it is easy to handle just by passing task2 as callback function for task1. what if there are nested dependencies,say task5 depends on task4 which in turn depends on task3 which in turn depends on task3 and then task1. So, the execution order would be
Task1–>Task2–>Task3–>Task4–>Task5
Multiple chained asynchronous tasks, requires to define callback functions within callback functions within callback functions…(i.e, multi level nested callback functions). The code becomes messy and it is difficult to maintain such code .This is referred as callback hell.

Promise:

Promise was introduced as an alternative to callbacks  to get rid of the callback hell.
Callback function is passed as an argument to a function and gets executed once the dependant asynchronous task completes whereas in the case of promise, the asynchronous function returns a special object called promise which can be used to determine or handle further task.
Originally Promise was a type of construct introduced by JavaScript libraries like Q and Bluebird , but these types of libraries became popular enough that promises are now provided natively in ES6.
A promise could be in 3 states – pending, fullfilled and rejected.
Pending – Initial state and the task is not yet complete
fullfilled – The state of a promise representing a successful operation
rejected – The state of a promise representing a failed operation.(say in case of any exception or unexpected result)
With this brief introduction to promise , let us get back to our previous example of placeOrder() and getItems() and see how this can be handled using promises

 
Output1 (when itemavailable=true)

Output2 (when itemavailable=false)
What if there is no catch statment in the above code,

Output(when itemavailable=false and no catch statement)

It is always advisable to add a catch statement to gracefully handle the exception.

 Promises chaining:

Let us see how the callback hell problem is gracefully handled with promises. When there are multi level dependencies say, Task3 depends on Task2 which in turn depends on Task1, the execution order would be Task1–>Task2–>Task2.
This can be achieved using promises chaining
In our previous example , let us assume after placing order , 3 task has to be performed one after the other(say , task1 followed by task2 and task3)
We can use multiple then statement to achieve this multi level dependencies and this is called promises chaining
some thing like this,
placingOrder()
.then(task1)
.then(task2)
.then(task3)

 

Output:

Using fetch api and promise:

In the above section, we discussed about creating our own promise whereas there are many javascript libraries that uses promises like mongodb and most of the time we deal with handling the response rather than creating a new promise.
This example illustrates how to make network request using fetch() method and handle the promise returned by the method to print the response data.

Promises in parallel:

If a task depends on multiple independent asynchronous task, say task4 depends on task1, task2 and task3 which are independent of each other, then promise.all can be used to execute task1, task2, task3 in parallel and once all these task are complete, then can be used to execute task4.

some thing like this,

Promise.all([task1,task2,task3])

.then(task4)


 

In the above sample code, task1,task2 and task3 are independent asynchrnous task which returns 3 different integers 5,6 and 7 and the 4th task(then block) which is dependent on all these tasks, calculates the sum of all these integers 5+6+7=18. Here task1,task2 and task3 take 2000ms,1000ms and 500ms respectively and the total execution time of all these 3 task using promise.all would be 2000ms (i.,e max of all 3)

Output:

Async/Await:

Async Await is a syntactic sugar around Promises introduced in EcmaScript 8 which helps to write asynchronous code organized like a synchronous one.

Async function:

Async functions enable us to write promise based code as if it were synchronous, but without blocking the execution thread.
An asyn function operates asynchronously via the event loop, using an implicit Promise to return its result i.e., Async functions will always return a promise and if a promise is not returned, JavaScript automatically wraps it in a resolved promise with its value.

 

Output:

await expression:

The await expression is used to wait for a Promise and can be used only inside an Async block. The keyword Await makes JavaScript waits for the Promise’s resolution. Please note that, await expression makes the async function block alone to wait and not the whole program execution.(i.e, does not block the main thread)
let us get back to our previous example of placeOrder() and getItems() and see how this can be handled without then but using  async/await ,

Output:
The output is same as using then on promise

async/await error handling :

When using async await, make sure to use try catch for error handling.

Example: try catch is added to the above mentioned orderAndGetItems(),

Output1 (when itemavailable=true)
Output2 (when itemavailable=false)

 

Hope this article helps you to get comfortable with the asynchronous javascript using callback, promises and async/await. leave a comment if you have any queries.