Promises: async/await vs .then(), how we got here and why I use both
Tags: javascript, typescript, react, node
Published: 2022-03-19 13:44:25

---
title: Promises: async/await vs .then(), how we got here and why I use both
published: true
canonical_url: https://abdellahcodes.com/promises-asyncawait-vs-then-how-we-got-here-and-why-i-use-both
tags: [javascript, typescript, reactjs, nodejs]
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7kdq72js2t5pqg64i89t.png
---

## How we got here

Promises marked a huge turning point in async js, they enabled a new type of control flow that saved us from callback hell. But some people found that calling `.then()` multiple times was too much, too callbacky.

Then after a while, we resorted to [generator functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator) and cogenerators, which made async code feel like its synchronous, at the cost of wrapping it in a generator function, `yield`ing every line and introducing a cogenerator library (for example [co](https://www.npmjs.com/package/co)) to deal with unwrapping the promises like the following example, where we could just `yield` a promise whenever we encounter it and pretend that the `yield` does not exist on that line of code.

```js
co(function* () {
  let result1 = yield somePromise1
  let result1 = yield anotherPromise
  dostuff(result1, result2)
})
```

This evolution served as the inspiration of the `async/await ` syntax introduced in [es7](https://github.com/tc39/proposal-async-await), and finally we could just

```js
let value = await somePromise
doStuff(value)
// instead of
somePromise.then(value => doStuff(value)
```
Oh, and you had to wrap it in an [`async` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) to be able to use it, but that's  changing with top level `await`.

## Why I use both
One simple reason: error handling.

Writing code for the happy path feels good, if only the world were a perfect place. But hélas, if you omit error handling during development, you will pay for it later while digging through a mysterious bug report.

Promises have a `.catch(callback)` method similar to `.then(callback)` where the `callback` expects an error.

```js
myPromise
    .then(value => handleHappyPath(value))
    .then(value2 => handleAnotherHappyPath(value2))
    .catch(err => handleError(err))
```

The `async/await` version looks like this:

```js
try {
    let value = await myPromise
    let value2 = await handleHappyPath(value)
   handleAnotherHappyPath(value2)
} catch(err) {
    handleError(err)
}
```

One least used - but very useful - feature of `.then` is that it accepts a second parameter as an error handler.

```js
myPromise
    .then(handleHappyPath, handleErrorScoped)
    .then(anotherHappyPath)
    .catch(err => handleError(err))
```

In this example, `handleErrorScoped` will take care of errors for this particular step. While `handleError` will  handle errors of the whole chain (including errors inside `handleErrorScoped`).

The equivalent `sync/await` version requires a nested `try/catch` block.

```js
try {
    let value
    try {
        value = await myPromise
    } catch (err) {
        // possibly setting `value` to something
        handleErrorScoped(err)
    }
    let value2 = await handleHappyPath(value)
   handleAnotherHappyPath(value2)
} catch(err) {
    handleError(err)
}
```

Maybe it's just me, but I find the latter a hell of lot more verbose, running away from callback hell, ran directly into `try/catch` hell.

An example of an instance where I found myself combining both is when I use puppeteer to check if an element exists in a page.

```js
let hasElement = await page.evaluate(() => document.querySelector("some selector"))
    .then(() => true)
    .catch(() => false)
```

## Conclusion

`async/await` was a huge stepping stone towards simplifying async javascript, but it does not obsolete `.then()` and `.catch()`, both have their use cases, especially when
we need granular control over error handling.

A combination of both seems to give the most readable code, robust and maintainable code.

If you  made it this far, please show your support with reactions and don't hesitate to 
ask question within comments, I'd love to answer each one of them and know your thoughts about the dichotomy of `async/await` vs `.then()` 🙂