---
title: Good Things Come to Those Who Await
teaser: 'How using async/await can make your async JavaScript code clearer.

  '
tags: javascript,web
author: Tom Wey
published_on: 2018-06-04
---

[ES8], otherwise known as ES2017, introduced `async`/`await` as an alternative
to using [Promises] directly for writing and interacting with asynchronous code.

[ES8]: https://www.ecma-international.org/ecma-262/8.0/index.html
[Promises]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

## Using async/await

The [`async` function] \(or its counterpart, the [`async function` keyword]) and
the [`await` expression] can be combined to produce asynchronous code that
reads similarly to synchronous code.

Specifying that a function is `async` has two main effects:

1. It causes the return value of the async function to be a Promise resolving
  with the return value of the original, passed function.

2. It allows us to use the `await` expression within the function.

[`async` function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
[`async function` keyword]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/async_function
[`await` expression]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

## Examples

It's probably easiest to illustrate with some examples. The following is the
most basic case:

```javascript
const plainFunction = () => "bar";

const asyncFunction = async () =>
  plainFunction()

plainFunction() // => "bar"
asyncFunction() // => a Promise which resolves with "bar"
```

Following on from this, if we have a function which itself is asynchronous (i.e.
returns a Promise), in our `async` function we can call it, pause execution and
wait for it to complete before continuing, using `await`:

```javascript
const fetchAndTransformPost = async () => {
  const response = await fetch("https://api.example.com/v1/posts/1");
  const post = await response.json();
  const transformedPost = transformPost(post);
  return transformedPost;
};

fetchAndTransformPost() // => a Promise which resolves with `transformedPost`
```

Let's break this down:

1.  The `fetch` call returns a promise:

    ```javascript
    const response = await fetch("https://api.example.com/v1/posts/1");
    ```

    The presence of `await` causes us to suspend execution of this code path
    until the promise has resolved. Once resolved the return value is the value the
    promise resolves with, in this case a `Response` object. So this is the value
    we assign to `response`.

2. Next we decode the JSON body of the response:

    ```javascript
      const json = await response.json();
    ```

    Again this call is asynchronous and returns a promise. As above we suspend
    execution of this code until the work is complete. The return value, and
    assignment, is the value of the resolved promise, in this case a JavaScript
    data structure representing the decoded JSON.

3. The final part performs some transformation on the decoded JSON and returns the
   transformed data:

    ```javascript
      const transformedJson = transformJson(json);
      return transformedJson;
    ```

    The return value of `fetchAndTransformJson` is a Promise which resolves
    with `transformedJson`.

In here we have two function calls which return promises - `fetch()` and
`response.json()`. Without `async`/`await` we'd have used `then` to create a
promise chain. What I like about this is how much it looks like regular old
sychronous JavaScript code (ignoring the fact that we're probably mixing too
many concerns in this one function!)

## More complex scenarios

So far our examples have been fairly straightforward. I think where
`async`/`await` really shines is in more complex scenarios where we have
synchronous code interspersed with our async code.

In this example we fetch a post from an API endpoint and, if its status is
"published", fetch its comments from another API endpoint and merge them in:

This is how it looks written with `async`/`await`:

```javascript
const withAsyncAwait = async () => {
  const response = await fetch(postEndpoint);
  const post = await response.json();

  if (post.status === "published") {
    const commentsResponse = await fetch(commentsEndpoint);
    const comments = await commentsResponse.json();

    return { ...post, comments };
  } else {
    return post;
  }
};
```

This is the equivalent written using the `Promise` API directly:

```javascript
const withPromises = () =>
  fetch(postEndpoint)
    .then(response => response.json())
    .then(post => {
      if (post.status === "published") {
        return fetch(commentsEndpoint)
          .then(commentsResponse => commentsResponse.json())
          .then(comments => ({ ...post, comments }));
      } else {
        return post;
      }
    });
```

I find the `async`/`await` version more readable and easy to follow. I like how
flat it is, and aside from the additions of `async` and `await` it reads just
like synchronous code.

## Concurrent async operations

Sometimes it's necessary to trigger multiple asynchronous operations
concurrently, and wait for them all to complete before returning. Using `await`
alone doesn't cut it, since it always waits for the operation to complete
before continuing. Let's say we have two asynchronous operations, which we want
to wait for and then return in a single comma
separated string:

```javascript
const multi = async () => {
  const result1 = await generateResult1();
  const result2 = await generateResult2();
  return [result1, result2].join(",");
}
```

This will have the return value we're looking for, but `generateResult2` won't
run until `generateResult1` has finished. Since there's no dependency, there's
no need to wait. Instead, we need to lean on `Promise.all` and `await` the
result of that before continuing:

```javascript
const multi = async () => {
  const results = await Promise.all([generateResult1(), generateResult2()]);
  return results.join(",");
}
```

## Top level handling

We can't always escape the fact that, behind the nice syntax provided by
async/await, we're dealing with Promises.

At the entry point to our top level async code we probably want to ensure that
we're handling any errors which may occur in our downstream async code with a
catch handler:

```javascript
asyncFunction()
  .catch(error => console.log("Something went wrong: ", error));
```

Alternatively within our `async` functions we could wrap any `await` calls with
a [`try`/`catch`] block to handle downstream failures and ensure we don't
return a rejected promise:

```javascript
const asyncFunction = async () => {
  try {
    return await thisMayFail();
  } catch(e) {
    return DEFAULT;
  }
};
```

Likewise, because we can't use `await` outside of an `async` function, if we
care about the final return value of our async code, we have to use the
`Promise` API directly and use `then`:

```javascript
asyncFunction()
  .then(result => console.log("Something went right:", result))
  .catch(error => console.log("Something went wrong: ", error));
```

[`try`/`catch`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch

## Wrapping Up

I've been using `async`/`await` liberally on a project and have been really
happy with the improvements it's brought to code readability, especially in
more complex cases involving logic based on the result of async operations.

There's reasonable [browser support] for `async`/`await` and it's available in
recent [Node versions], but depending on your use case you may need to leverage
a tool like [Babel] to make use of it.

[browser support]: https://caniuse.com/#feat=async-functions
[Node versions]: https://node.green/#ES2017
[Babel]: https://babeljs.io
