We all know that Javascript is a single-threaded. This means it has one call stack and one memory heap. I have already written an article on this topic, you can learn more about the call stack, event loop before going through the rest of this article. In this article, we are going to learn some of the javascript fundamental concepts in more details. This includes callback, promise and async/await.

Single thread raise problem in javascript. What happens when javascript calls any slow process? A browser would become locked and on server-side node.js would not able to perform any further user request.

So how to handle this problem in the javascript?

The solution is to use asynchronous operations in javascript.

In asynchronous operation, the execution will never wait to complete, instead, it will execute all the operation in one go. For asynchronous operations, all the tasks will be executed simultaneously, and it will be handled once the result of each task is available.

Callback function In JavaScript

The callback function accepts another function as an argument. Before the ES6 Introduction, you can find callback function in almost all javascript code.

In the callback function, when the first function is executed then it will run the second function.

A simple callback function looks like below code

const getArticles = callback => {
    setTimeout(() => {
       callback ({ title : 'I am callback function title' })
    }, 1000)
}

getArticles(article => {
    console.log(article.title);
});

In the above code, we are using the arrow functions getArticles to get the list of the articles. In the getArticles function, again we are using the setTimeout function to delay the execution of the code for 1 sec.

You can see in the code, instead of using the return keyword, we are using a callback to return the required object.

Now when we will call the getArticles function it will print the object after 1 sec.

callback hell

Sometimes while doing the coding, we have to deal with multiple requests and each request is dependent upon the result of the previous request.

Let’s understand this with an example. Suppose you have a user’s collections. Once you have user then you want to get the articles written by that user, now when you have the list of articles written by that user, you also need to fetch the comments from that articles.

This is known as callback hell. Let’s see an code example of the above situation:

getUser(1, (user) => {
    getArticles(user.name, (articles) => {
        getComments(articles[0], (comments) => {
            console.log(user, article[0], comments);
        })
    })
});
 
function getUser(id, callback) {
    setTimeout(() => {
        console.log('Getting the user from the database...');
        callback({
            id: id,
            name: 'sachin'
        });
    }, 1000);
}
 
function getArticles(username, callback) {
    setTimeout(() => {
        console.log('Calling API for articles');
        callback(['Article1', 'Article2', 'Article3']);
    }, 1000);
}
 
function getComments(article, callback) {
    setTimeout(() => {
        console.log('Calling API for comments for ' + article);
        callback(['comments for ' + article]);
    }, 1000);
}

As you can see, it is not easy to read the code and understand it in the first attempt. This is one of the most simple examples of the callback hell when you have many nested functions, code will more complex and there might be a chance of introducing bugs.

To overcome with this issue of callback hell, We are using the promises in Javascript.

Promise In JavaScript

Promise is a build in language feature. A Promise is used to handle the asynchronous result of an operation.

Javascript Promise makes handling of asynchronous operation easier and more readable.

Promises in Javascript have following three states:

  • Pending: This is the initial stage of the promise.
  • Fulfilled: This means the process completed
  • Rejected: This means the process didn’t complete.

Create Promise in Javascript

In JavaScript, a promise object is created using the new keyword followed by the Promise.

const promise = new Promise(function(resolve, reject) { 
// promise code goes here 
});

How to use Promise function in JavaScript

Promise can be use by using the then and catch keyword like below example

promise
  .then(function(done) {
    // the content from the resolve() is here
  })
  .catch(function(error) {
    // the info from the reject() is here
  });

convert callback function into promise

Now, we learn how to create and use promise in the Javascript.

Let’s convert our callback function into the promise.

getUser(1)
    .then(user => getArticles(user.name))
    .then(articles => getComments(articles[0]))
    .then(comments => console.log(comments))
    .catch(err => console.log('Error: ', err.message));
 
function getUser(id) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('Getting the user from the database...');
            resolve({
                id: id,
                name: 'sachin'
            });
        }, 1000);
    });
}
 
function getArticles(username) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('Calling API for articles');
            resolve(['Article1', 'Article2', 'Article3']);
        }, 1000);
    });
}
 
function getComments(article) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('Calling API for comments for ' + article);
            resolve(['comments for ' + article]);
        }, 1000);
    });
} 

From the above code, you can see promise makes our code cleaner and more readable then the callback functions.

Also we remove the callback hell issue with the promise chaining.

Async/Await In JavaScript

Async/await is know as the syntactic sugar. It only makes writing promises easier.

Async/await always returns a promise. If function return value then promise will be resolved with the value but if function throws any error then promise is rejected with that value.

You can also tell that async/await is the newest version to overcome the issue of callback hell.

Now let’s convert our above code into async/await

async function displayArticlesComments() {
    try {
        const user = await getUser(1);
        const articles = await getArticles(user.name);
        const comments = await getComments(articles[0]);
        console.log(comments);
    } catch (err) {
        console.log('Error', err.message);
    }
}

You can see async/await makes our code more cleaner and easy to read.

Here you can see two new javascript keywords async and await.

Await is only used with an async function. The await keyword is used in an async function to ensure that all promises returned in the async function are synchronized.

Above code now looks like it is synchronous but actually it is asynchronous in the background. This is the beauty of using the async/await in javascript.

There are few things which you have to keep in mind while using the async/await.

  • the outer function must be preceded by an async statement
  • calls to asynchronous Promise-based functions must be preceded by await
  • function before which you are using the await keyword must return promise

Conclusion

No doubt that asynchronous programming in javascript is difficult to learn in the first attempt. But if you have a good understanding of how callback, promise and async/await works and how to use them then it will become easy for you.

These concepts will come handy when you are going to deal with the different restful APIs requests.

Hope this article will help you clear your doubt on callback, promise and async/await. If you have any suggestion or doubt then you can comment in the comment box or can join our Facebook group where like-minded people will try to solve your queries.

References:

Codecademy Pro
Pin It