JavaScript's Async + Await in 5 Minutes
Tags: javascript, webdev, typescript, beginners
Published: 2019-12-14 13:22:38

> Bye Bye Promise inception and callback fury! 👋🎉

It’s likely that you’ve encountered Promises in your JavaScript (_If you haven’t check out this [guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) quick 👍_). They allow you to hook into the completion of asynchronous calls. They make it simple to chain asynchronous operations or even group them together. There is one tiny downside. When consuming Promises, the syntax isn’t always the prettiest.

Introducing __async__ + __await__ 🎉

For those in camp __TL;DR__ `async` + `await` are syntactic sugar for consuming your `Promise`s 🍭 They aid in understanding the flow of your code. There are no new concepts, it’s `Promise`s with nicer shoes 👟 Scroll down for a `gist` ⌨️

## Baking a cake with code 🍰
We are going to bake a cake 🍰 yum! To bake the cake, we first need to get the ingredients. I’m sorry, it’s a plain sponge 😅

* Butter
* Flour
* Sugar
* Eggs 🥚

In our code, getting each ingredient requires an asynchronous operation.

For example, here is the method `getButter`:

```javascript
const getButter = () => new Promise((resolve, reject) => {
  setTimeout(() => resolve('Butter'), 3000)
})
```

These operations will become part of a `getIngredients` method. When we bake the cake, we will need to invoke `getIngredients` before mixing, etc.

## With Promises

Let’s assume we need to chain each asynchronous operation. `getIngredients` is a journey around a supermarket picking up one ingredient at a time 🛒

In most cases, we only need to chain operations if they are dependent on each other. For example, if the second operation needs the return value from the first operation and so on.

In our example, it may be that we can only add one item to our shopping basket at a time. That means we need to progress through the ingredients one by one. Remember the code here is hypothetical and to show the use of Promises 😉

How might `getIngredients` look with Promises? I’ve certainly seen nested Promises like this before 👀

```javascript
const getIngredients = () => new Promise((resolve, reject) => {
  getButter().then((butter) => {
    updateBasket(butter)
    getFlour().then((flour) => {
      updateBasket(flour)
      getSugar().then((sugar) => {
        updateBasket(sugar)
        getEggs().then((eggs) => {
          updateBasket(eggs)
          resolve(basket)
        })
      })
    })
  })
})
```

This works but doesn’t look great 👎 It would look better with a Promise chain.

```javascript
const getIngredients = () => getButter()
  .then(updateBasket)
  .then(getFlour)
  .then(updateBasket)
  .then(getSugar)
  .then(updateBasket)
  .then(getEggs)
  .then(updateBasket)
```

If we were doing our grocery shopping online, we could use `Promise.all` 🤓

```javascript
const getIngredients = () => Promise.all([
  getButter(),
  getFlour(),
  getSugar(),
  getEggs(),
])
```

These look much tidier but we still need to use a callback to get those ingredients.

```javascript
getIngredients().then(ingredients => doSomethingWithIngredients(ingredients))
```

## Tidying it up with async + await

Let’s sprinkle on that syntactic sugar 🍭 To use the `await` keyword, we must first declare a method as asynchronous with the `async` keyword. It’s important to note that an `async` method _will always_ return a `Promise`. That means there is no need to return a `Promise` 🎉

Let’s declare `getIngredients` as async

```javascript
const getIngredients = async () => {}
```

Now, how might those `Promise`s look with sugar? The `await` keyword allows us to wait for a `Promise` and define a variable with the return value of that `Promise`. It's a little verbose for this example, but let’s apply that sugar to `getIngredients`.

```javascript
const getIngredients = async () => {
  const butter = await getButter()
  const flour = await getFlour()
  const sugar = await getSugar()
  const eggs = await getEggs()
  return [
    butter,
    flour,
    sugar,
    eggs,
  ]
}
```

The code isn't smaller, but it's more verbose and concise 👍 No more callbacks. It's when we consume a `Promise` that the syntactic sugar comes into play.

```javascript
const bakeACake = async () => {
  const ingredients = await getIngredients()
  // do something with the ingredients, no more ".then" 🙌
}
```

Wow! 😎 How much cleaner is that?

The use of `async` and `await` makes our code procedural and comprehensive. It looks cleaner and does exactly the same thing.  It’s important to remember here that we aren’t replacing `Promise`s, we're still using them under the hood. Now we're using them with a new cleaner syntax.

And yes, this works with `Promise.all` too. So if we had done the shopping online, our code gets even smaller.

```javascript
const getIngredients = async () => {
  const ingredients = await Promise.all([
    getButter(),
    getFlour(),
    getSugar(),
    getEggs(),
  ])
  return ingredients
}
```

We don't need that wrapper function anymore!

```javascript
const getIngredients = async () =>
  await Promise.all([getButter(), getFlour(), getSugar(), getEggs()]);
```

## Awaiting a non-Promise

How about if the value you `await` on is not a `Promise`? In our example, the asynchronous functions are returning a `String` after a `setTimeout`.

```javascript
const egg = await 🥚
```

There will be no error, the value becomes a resolved `Promise` 😅

## What about rejections?

Up until now, we’ve dealt with the happy path 😃 But how about in the case where a `Promise` rejects?

For example, what if there are no eggs in stock? Our asynchronous function for `getEggs` would reject with a potential error.

To accommodate for this, a simple `try`/`catch` statement will do the trick 👍

```javascript
const getIngredients = async () => {
  try {
    const butter = await 'Butter'
    const flour = await getFlour()
    const sugar = await getSugar()
    const eggs = await getEggs()
    return [
      butter,
      flour,
      sugar,
      eggs,
    ]
  } catch(e) { return e }
}
```
We could wrap at this level or higher up where we invoke `getIngredients` 👍

## Consuming our function and baking the cake 🍰

If you’ve got this far, we’ve created our function for `getIngredients` with the new `async` + `await` keywords. What might the rest of it look like?

```javascript
const bakeACake = async () => {
  try {
    // get the ingredients
    const ingredients = await getIngredients()
    // mix them together
    const cakeMix = await mix(ingredients)
    // put in oven on 180C, gas mark 4for 20-25 minutes
    const hotCake = await cook(cakeMix)
    // allow to stand before serving
    const cake = await stand(hotCake)
    return cake
  } catch (e) { return e }
}
```

Much cleaner than what we might have done previously with `Promise`s 🎉

## That’s it! Baking a cake with async + await in 5 minutes 🍰

If you’ve got this far, thanks for reading 😃 I’ve put together a gist with some possible example code that can be seen below along with some further resources on `async` + `await`.

The important takeaways ⚠️;
* `async` functions will always return a `Promise`
* `await` will in most cases be used against a `Promise` or a group of `Promise`s
* Handle any potential errors with a `try`/`catch` statement 👍
* We haven’t touched on this but you can `await` an `await`. Making a `fetch` request you might `await` the request and then `await` the `json` function.
```javascript
const data = await (await fetch(`${dataUrl}`)).json()
```

As always, any questions or suggestions, please feel free to leave a response or [tweet me 🐦](https://twitter.com/@jh3yy)! Be sure to follow me on the socials 😎

{% gist https://gist.github.com/jh3y/c7870ca6fb01d5e8577a9f1474a2c162 %}

### Further resources
* [`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) — MDN
* [`async` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) — MDN
* [Async + Await podcast](https://syntax.fm/show/028/async-await) — Syntax.fm