Async Await in JavaScript

Viswesh Subramanian
JavaScript Store
Published in
4 min readFeb 19, 2018

When you hear async in JavaScript, you will get flashes of Callback and Promises. Add Async/Await to that list. Although the JS community won the battle of callback hell and ruled the Promised land (pun intended), we grew out of it. We were fed up of the thens, convoluted error handling and the general flow control.

With Async/Await –

  1. Brevity: No more thens and catches.
  2. Error handling: try, catch block will suffice to handle errors from promises. No need to error handle promises with its own catch.
  3. Nested flows: Even with promises, there is a possibility that callback hell would seep in with flawed patterns. With async await, we are finally free.
  4. Debugging: With Promises, breakpoints do not step over to the following thens. With await, stepping over next lines become a breeze (because they act as if they are synchronous).

But wait a minute, what is Async?

According to mdn,

When an async function is called, it returns a Promise.

When the async function returns a value, the Promise will be resolved with the returned value.

When the async function throws an exception or some value, the Promise will be rejected with the thrown value.

Ok, and what is Await?

An async function can contain an await expression, that pauses the execution of the async function and waits for the passed Promise’s resolution, and then resumes the async function’s execution and returns the resolved value.

If the above statements flew over your head, don’t worry — to understand async await, we need to understand Promises first.

Let’s say we are building a website to display all dog breeds. Here is how the data is retrieved with a promise –

const request = require("request");

const getBreeds = () => {
let url = "https:s//dog.ceo/api/breeds/list/all";
return new Promise((resolve, reject) => {
request(url, (err, resp, body) => {
if (err) {
reject(err);
}
resolve(JSON.parse(body));
});
})
};

getBreeds function returns a Promise. If the request is successful, the promise is resolved with the body and if not, the promise is rejected.

getBreeds().then((response) => {
console.log(response);
}).catch((err) => {
console.error(err);
});

Great! What if there are multiple synchronous calls after getting a list of breeds? To contrive an example, let’s pick a winner from a list of breeds.

/**
* Pick a winner from a list of breeds
*
@returns {Promise.<void>}
*/
const pickWinner = async () => {
getBreeds().then((response) => {
console.log("First chain");
return response;
}).then((response) => {
console.log("Second chain");
return getWinner(response);
}).then((winner) => {
return winner;
}).catch((err) => {
console.error(err);
});
};

The chained ‘thenables’ look readable and clean but it has the ‘smarts’; only the trained eye will know that its a bunch of async code blocks.

Rewriting Promise chains with Async / Await –

/**
* Pick a winner from a list of breeds
*
@returns {Promise.<*>}
*/
const pickWinner = async () => {
try {
let breeds = await getBreeds();
let winner = await getWinner(breeds);
return winner;
} catch (error) {
throw Error(error);
}

};

This looks way more readable! With Async functions, you can write async, promise-based code as if it were synchronous. With await keyword, we wait for all the breeds to be retrieved. Once they are retrieved, the execution is resumed to the next line. Once a winner is identified, the async function is resolved with the winner.

Error handling is achieved with a simple try/catch block. It not only handles errors thrown by synchronous code but also asynchronous code. Fancy!

In summary –

  1. Async/Await is used with Promises.
  2. Async/Awair cannot be used with callbacks
  3. It makes async code look and behave line sync code.
  4. await keyword can be used only within functions with async keyword.
  5. Async functions return a promise. (return resolves the promise, throw Error(‘bar’) rejects the promise.)

There will be times when you don’t want to await each promise. What if you want to send parallel requests?

Answer: Use Promise.all()

Building up on our dog breeds example, lets a) get available breeds b) send parallel requests to fetch images of all the breeds.

/**
* Returns breed images
*
@returns {Promise.<*[]>}
*/
const getAllBreedsImages = async () => {
let breeds = Object.keys((await getBreeds()).message);
let breedsImages = await Promise.all(breeds.map(async breed => {
let response = await fetchImage(breed);
return response.message;
}));
return breedsImages;
};

As you can notice, we use a mixed mode — a combination of Promise and Asycn Await. By wrapping async calls with a Promise.all(), network requests are initiated in parallel.

Async Await is a great addition to JavaScript. Once you go Async Await, I promise you, you will not go back!

Reference:

https://developers.google.com/web/fundamentals/primers/async-functions

Originally published at javascriptstore.com on February 19, 2018.

--

--

Viswesh Subramanian
JavaScript Store

Full stack JS developer. Software generalist for the most part.