Asynchronous Javascript: From Callback to Async Await

    Jan 15, 2020       by Pankaj Kumar
javascript-from-callback-to-async-await.jpg

As we all know that Javascript has completely changed the Web development World. There was a time when Javascript was only used for front end validations and other basic tasks, But after Node.js and other front end frameworks like Angular, React etc, Javascript is used for complete web development. You can understand the importance of Javascript from the fact that It is one of the most demanding languages today.

popularity of javascript

In this article, I will explain the different ways to make an asynchronous call in Javascript. 

 

What is Asynchronous Javascript in actual?

Imagine requesting some data from an API. Depending upon the situation the server might take some time to process the request while blocking the main thread making the web page unresponsive.

That’s where asynchronous JavaScript comes into play. Using asynchronous JavaScript (such as callbacks, promises, and async/await), you can perform long network requests without blocking the main thread.

 

Simple Asynchronous JavaScript

setTimeout(function (){
  console.log('console when five seconds have passed.');
}, 5000);

console.log('End Line');

 

If we run the above program on the browser then, It will print like below:

second line

console when five seconds have passed.

 

What is happening behind?

The setTimeout() function takes a function to call when the timeout has elapsed, and a number of milliseconds to wait before calling that function. When we make a call to setTimeout() it is a call to a C++ API. This gets moved off of the execution stack and when the timeout completes, the callback gets pushed into the queue. Once the execution stack is empty, the event loop will pull the callback from the queue and add it to the execution stack. 

 

Callbacks(Beginning Approach)

It is very oldest approach for making an Asynchronous call in javascript. In this approach we mainly pass the last parameter as the callback function. Let's have a look at example below:

 
  const MongoClient = require('mongodb').MongoClient;
 
  MongoClient.connect('mongodb://localhost:27017/test-app', (err, db) => {
    if (err) throw err;
    console.log("Connected to MongoDB!");
    db.close();
  });
 

 

The above example shows the another common pattern for callbacks, and that is the first parameter of the callback function is an error result. This allows the callback to check for an error result first and go ahead and throw or handle the error before trying to read a result it probably doesn’t have.

Drawbacks of Callback

  • Callback hell
  • Problem when performing database operation within any loop(synchronous task).

To overcome the issues with Callbacks, Promise became very popular.

 

Promise(Way to resolve the hurdle of callbacks)

A promise is an object that may produce a single value some time in the future: either a resolved value, or a reason that it’s not resolved (e.g., a network error occurred). A promise may be in one of 3 possible states: fulfilled, rejected, or pending. Promise users can attach callbacks to handle the fulfilled value or the reason for rejection.

Promises were introduced to fix a lot of the problems with using callbacks to do asynchronous operations. 

 

Basic Syntax

 
let promise = new Promise(function(resolve, reject) {
// do a thing, possibly async, then…
 
  if (/* everything turned out fine */) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke"));
  }
});
 

 

Let's create own Promise to create database connection and call it.

 

 
const MongoClient = require('mongodb').MongoClient;
const database;
 
function connectToMongo(url){
  return new Promise((resolve, reject) => {
    MongoClient.connect(url, (err, db) => {
      if (err) reject(err);
       resolve(db);
    });
  });
}
 
connectToMongo('mongodb://localhost:27017/test-app')
.then((db) => {
  database = db;
  return db.queryTheDatabase();
})
.then((res) => {
  doSometingWithResults(res);
  database.close();
})
.catch((err) => {
  console.error(err);
});

 

In the above example, the MongoClient.connect() function is wrapped to return a promise while the callback is being processed. Once the callback is called, it either resolves or rejects the promise. When we call the connectToMongo() function, we get that promise back. Then chain then() function calls onto the promise. Each then returns a promise, and in the first then() the promise resolves with the database query results. If there is an error and the promise is rejected, I handle it here with the catch() function.

 

Async/Await(Latest Approach)

It also works like promises behind the scene, But syntax is shorter than the promise and code becomes more readable with Async/Await. 

Let's understand it with example:

 

 
const MongoClient = require('mongodb').MongoClient;
 
function connectToMongo(url){
  return new Promise((resolve, reject) => {
    MongoClient.connect(url, (err, db) => {
      if (err) reject(err);
       resolve(db);
      }); 
    });
}
 
async function getAllUsers(){
  try{
    const db = await connectToMongo('mongodb://localhost:27017/test-app');
    const users = await db.collection.Users.find({});
    db.close();
    return users;
}catch(err){
  console.error(err);
  return err.message;
  }
}
 

 

For using Async/Await. It is necessary to use Async keyword before the function keyword and await is used where we are making the call. In the above example, connectToMongo is a method  which is returning promise which is handled with the await. So await can be used only at the function which is returning a promise. That's why I written earlier that Async/Await works like Promises behind the scene.

 

Click here to find Sample Applications on different javascript frameworks.

Let me know your thoughts over the email demo.jsonworld@gmail.com. I would love to hear them and If you like this article, share with your friends.

Thank You!


WHAT'S NEW

Find other similar Articles here: