5 Reasons Why JavaScript Async/Await Over Promises
Tags: javascript, programming
Published: 2021-05-09 13:48:50

NodeJS supports async/await out of the box since version 7.6. I believe this is one of greatest addition to JS since 2017. If you haven’t tried it yet, here are 5 main reasons reasons with examples why you should adopt it immediately and never look back.

## What is Async/Await

Async/await is a new way to write asynchronous code. Previous alternatives for asynchronous code are callbacks and promises. Async/await is actually just syntax built on top of promises. It cannot be used with plain callbacks or node callbacks. 

## Syntax for Async/Await and Promises

```js
const makeRequest = () =>
  getJSON()
    .then(data => {
      console.log(data)
      return "done"
    })

makeRequest()
```
And this is how it looks with async/await:
```js
const makeRequest = async () => {
  console.log(await getJSON())
  return "done"
}

makeRequest()
```
## Why Is It better?

 **1. Clean Code**
If you compare above code then async/await code is much cleaner compare to promises

 **2. Error Handling**
Async/await makes it finally possible to handle both synchronous and asynchronous errors with the same construct, good old `try/catch`
```js
const makeRequest = () => {
  try {
    getJSON()
      .then(result => {
        // this parse may fail
        const data = JSON.parse(result)
        console.log(data)
      })
  } catch (err) {
    console.log(err)
  }
```
Now look at the same code with async/await. 
```js
const makeRequest = async () => {
  try {
    const data = JSON.parse(await getJSON())
    console.log(data)
  } catch (err) {
    console.log(err)
  }
}
```
 **3. Return Conditional Data**
 ```js
const makeRequest = () => {
  return getJSON()
    .then(data => {
      if (data.needsAnotherRequest) {
        return makeAnotherRequest(data)
          .then(moreData => {
            console.log(moreData)
            return moreData
          })
      } else {
        console.log(data)
        return data
      }
    })
}
```

Above example is so messy and nested syntax are really tough to understand.

Look at the same code with async/await. 
```js
const makeRequest = async () => {
  const data = await getJSON()
  if (data.needsAnotherRequest) {
    const moreData = await makeAnotherRequest(data);
    console.log(moreData)
    return moreData
  } else {
    console.log(data)
    return data    
  }
}
```
 **4. Intermediate values**

You might have a situation where you call a `promise1` and then use what it returns to call `promise2`, then use the results of both promises to call a `promise3`. Your code most likely looked like this

```js
const makeRequest = () => {
  return promise1()
    .then(value1 => {
      // do something
      return promise2(value1)
        .then(value2 => {
          // do something          
          return promise3(value1, value2)
        })
    })
}
```
This same logic becomes very simple with async/await. 

```js
const makeRequest = async () => {
  const value1 = await promise1()
  const value2 = await promise2(value1)
  return promise3(value1, value2)
}
```
 **5. Debugging**
A killer advantage when using async/await is that it’s much easier to debug. Debugging promises has always been such a pain because of 2 main reasons:

 1). You can’t set breakpoints in arrow functions that return expressions.
 2). If you set a breakpoint inside a .then block and use debug shortcuts like step-over, debugger will not move to the the following .then because it only steps through synchronous code
```js
const makeRequest = () => {
   return callAPromise()
     .then(() => callAPromise())
     .then(() => callAPromise())
}
```
With async/await you don’t need arrow functions as much, so you can step through await calls exactly like normal synchronous calls.
```js
const makeRequest = async() => {
   await callAPromise()
   await callAPromise()
}
```