Explaining async await of ES8 with examples

Tue Feb 14 2017

Paul Shan

A much awaited feature async await is available on your browser now (if you’re using chrome 55 or greater). Firefox will start supporting from version 52 an Safari from 10.1. Others will also follow the path.

So, we can say we have entered the era of async await and now can handle our asynchronous programs with style :)

The journey of asynchronous

When it all started

Since birth JavaScript was asynchronous and we used to handle things with callbacks. So for long operations; it was like, a callback inside another callback, then another one inside that, then another. Used to look like something like below.

function lotOfAsyncWork() {
    request("/api/isLogin", function(response){
        var userId = response.loggedInUserId;
        request("/api/user/detsils/"+userId, function (response2) {
            request("http://github/repos/"+response2.repoName, function (response3) {
                paintTheUI(response3, function () {
                    hideLoader();
                });
            });
        });
    });
}

Promises to the rescue

Due to all those ugly callbacks, an english phrase was being attached to JavaScript. That was “callback hell”. The code used to look really ugly. Then people came up with promises which gave the control back to the callee function to execute any callback. Below is the promise based solution of the above snippet.

function fetchCurrentLogin() {
    return new Promise(function (resolve, reject) {
        request("/api/isLogin", resolve);
    });
}

function fetchUserDetails(response) {
    return new Promise(function (resolve, reject) {
        var userId = response.loggedInUserId;
        request("/api/user/detsils/"+userId, resolve);
    });
}

function fetchGithubDetails(response1) {
    return new Promise(function (resolve, reject) {
        request("/api/isLogin", resolve);
    });
}

function fetchCurrentLogin(response2) {
    return new Promise(function (resolve, reject) {
        request("http://github/repos/"+response2.repoName, resolve);
    });
}

function lotOfAsyncWork() {
    fetchCurrentLogin()
    .then(fetchUserDetails)
    .then(fetchGithubDetails)
    .then(paintTheUI)
    .then(hideLoader);
}

Problem of promise chain

Though the promises have resolved the issue of callback hell till a very good extent. But it also created a problem of promise chaining. Since our code is generally modular and different modules communicate with each other; we started creating a promise chain. And it’s another pain to create and return promises again and again.

promise chain diagram

Introduction to generators

ES6 came up with the concept of generators in which you can do pause and resume kind of operations. Generators can be used in many other corners too; but that pause feature with yield was useful to handle asynchronous in some cases.

Now it’s async await

ES8 came up with async and await keywords which can be used to symbolize a function as asynchronous and to wait or pause till the time it is not resolved. This feature is a mixture of promises and generators.

New async await syntax

The keyword async is used to declare a function as async. The syntax is as simple as putting an keyword async infront of function, which return an AsyncFunction object.


async function myFunc(){
    //function body
}

AsyncFunction object is like a promise. You can use the myFunc().then() function to execute some statements after your async function is completed fully.

Unlike a promise, an async function doesn’t have any resolve or reject callbacks; rather it waits using the await keyword just like the following way.

async function myFunc(){
    var result = await someAsyncFunction();
    return result;
}

You can also use multiple awaits inside a single await function like the following example.

async function myFunc(){
    var result1 = await someAsyncFunction();
    var result2 = await someOtherAsyncFunction();
    return result1 + result2;
}

Once all await are resolved in an async function, it will be considered as completed. The first async function may have a promise or could be using a promise object and the rest will simply await till the previous one is resolved. See the example below of a promise chain.

function baseAsyncFunctionWithPromise(argument) {
    return new Promise((resolve)=>{
        setTimeout(() => resolve(100), 10000)
    });
}

async function secondAsyncFunction() {
    var result = await baseAsyncFunctionWithPromise();
    return ++result;
}

async function finalAsyncFunc() {
    var result = await secondAsyncFunction();
    return ++result;
}

finalAsyncFunc().then((r)=>{
    console.log("finalAsyncFunc resolved with value ", r);
});

The above code snippet will finally print “finalAsyncFunc resolved with value 102”.

Callbacks & async-await

The rule is, you can not use await outside any async function. The immediate parent must be an async and that is the reason why the following code will throw a syntax error.


async function fetchHTML(urls) {
    urls.forEach(url => {
        // syntax error
        const content = await httpGet(url);
        console.log(content);
    });
    console.log("I am tricky");
}
The correct way to do that iteration is as below.

async function fetchHTML(urls) {
    urls.forEach(async url => {
        const content = await httpGet(url);
        console.log(content);
    });
    console.log("I am tricky");
}

However, If you think that "I am tricky" will be printed only after all the async calls are resolved, then you are wrong. Rather "I am tricky" will be printed before any httpGet(url) is resolved. And that is because no one is awaiting for the async callbacks (the await is only there for the httpGet()).

If you want to achieve the synchronous kind of behavior here, you will probably have to go with for of, so that you can avoid the callbacks. Below is the code.


async function fetchHTML(urls) {
    for (const url of urls) {
        const content = await httpGet(url);
        console.log(content);
    }
    console.log("I am tricky. But I will be printed at the end.");
}

Pros of async await

Sync like code

JavaScript is a single threaded language and it just can’t afford to block the thread to wait for an asynchronous function to get resolved. But the handling of asynchronous calls using promise or callback are really a little tough to understand. However async await gave us the power to make a code which looks like and also executes synchronously, but do not block the main thread. This is the reason to introduce async await; thus the biggest pro.

Less silent errors


async function foo() {
    throw new Error('Error!');
}
foo();

The code above would have silently throw an error in previous JavaScript ways, but now in majority of the browsers it's no more silent.

Cons of async await

A con with async await is, it awaits in one after another. Suppose you have a code like below.

async function myAsyncFunc(){
    return await asyncTask1() + await asyncTask2();
}

In this code, JavaScript will run asyncTask1() and will wait till it gets resolved. Then it will trigger asyncTask2() and do the similar thing. So if you don’t have any dependency between asyncTask1 & asyncTask2 and both of them can be triggered parallelly; using two awaits will kind of harm your performance. Though you are open to use Promise.all and await for a single promise returned by that.

SHARE THIS ARTICLE

post-thumbnail
Today everyone knows the importance of a lightning-fast website and how the speed impacts the conversion rate of a business. Today, everyone wants the site to be a PWA so that the mobile users can have an app-like experience with the website because, for the majority of the merchants, the customers come through mobile devices.
Tue Apr 20 2021
post-thumbnail
Here we are going to see how you can manage backup and restore of Postgres database with docker.
Thu Sep 03 2020
post-thumbnail
Image sliders or carousels always have increased the UI attraction of websites and they are pretty useful for reflecting the major roles/products too. In case, I am having a website that sells tee-shirts,
Mon Apr 30 2018

About VoidCanvas

This blog was created out of hobby and talks mostly about technology, web development, JavaScript, NodeJS and related topics. Thank you for reading my blog.

Copyright 2022 - www.voidcanvas.com

Popular Articles

Authentication using Google's oAuth api with node.js

Thu Mar 10 2016

OAuth authentications are pretty popular now a days and another thing which is popular is JavaScript. This article shows how to plugin google’s oAuth api for authentication in your own node application.

CSS3 Loader Snippet Collection: (Part 2 - Squares)

Sat Mar 01 2014

This is a continuation of my CSS3 loader snippet collection series. I've provided spinning css3 animation loader in the part 1 of this series and here in part 2, I'm providing various square type loading