3 ways to handle Async/await error.
Tags: javascript, webdev, beginners
Published: 2020-04-24 08:38:33

When comes to asynchronous operation, we always think about JavaScript Promise methods right? But there are other ways we can sort this out. I found the most profound way is `async/await`. `async` is used when we are writing any asynchronous operation and `await` is used when we are waiting for that asynchronous operation.

```typescript
const getPersons = async () => {
    // we are making the actual database ie REST api call
    return fetch('persons');
}

const process = async () => {
    // we are waiting for persons
    const persons = await getPersons();
    console.log(persons);
}
```

There are a number of ways we can handle errors in JavaScript. In this article, we'll talk about the 3 most used ways to handle `async/await` error.

## 1. Promise.catch

We know we can use promises with `async`. We'll add a catch block with the asynchronous method.

```typescript
const getPersons = async () => {
    return fetch('http://person')
        // here we added a promise catch method
        .catch(error => {
            //TypeError: Failed to fetch
            console.log(error);
        });
}

const process = async () => {
    const persons = await getPersons();
    console.log(persons); // undefined
}

process();
```

This way we can handle `unhandled promise rejection` error. But the downside of this approach is we have to add a catch method for each asynchronous operation.

## 2. A wrapper of Promise.catch

We can create a wrapper function so that we don't need to add the `catch` method of each asynchronous operation. 

```typescript
const asyncWrapper = async (promise) => {
    return promise.catch(error => {
        console.log(error); //TypeError: Failed to fetch
        return error;
    });
}

const getPersons = async () => {
    return asyncWrapper(fetch('http://person'));
}

const process = async () => {
    const persons = await getPersons();
    console.log(persons); //TypeError: Failed to fetch
}

process();
```

It is better hah? So, what we did here? We extract the `catch` method from `getPersons` to `asyncWrapper`. We handle the error inside the wrapper and return the error to the outside to show some error message to the user.

In this approach there are slight difficulties, each and every time we have to check, there is a valid person or not? This is tedious and there is no clear way to know that there is an error. We can solve this problem

```typescript
const asyncWrapper = async (promise) => {
    return promise
        .then(result => [null, result])
        .catch(error => [error]);
}

const getPersons = async () => {
    return asyncWrapper(fetch('http://person'));
}

const process = async () => {
    const [error, result] = await getPersons();
    console.log(error, result); //TypeError: Failed to fetch, undefined
}

process();
```

This is way better right? Here we use JavaScript destructing pattern. We add a `.then` method and return the success case as `[null, result]`. That means, if your asynchronous operation is successful, it will return the result where the error is `null`

On the other hand, we returned `[error]` means the result is `undefined`. It is other way around, when error is present there is no result and when the result is present there is no error! In this pattern, we clearly know when an error happened.

## 3. Promise.allSettled

We know `Promise.allSettled` is very powerful method where it shows the reason why your asynchronous operation is failed. If you want to learn more, check this article

https://dev.to/tasnimreza/3-most-powerful-javascript-promise-methods-2g8f

```typescript
const asyncWrapper = async (promise) => {
    const [result] = await Promise.allSettled([promise]);
    return result;
}

const getPersons = async () => {
    return asyncWrapper(fetch('http://person'));
}

const process = async () => {
    const { reason, value } = await getPersons();
    console.log(reason, value); //TypeError: Failed to fetch, undefined
}

process();
```

We use `Promise.allSettled` inside the wrapper and `await` to finish the job. When the asynchronous operation is finished, it destructing the result to the result array. Because `Promise.allSettled` always return array.

Finally we use object destructing to receive the result. As we know `Promise.allSettled` return `status, reason, value`. Here we ignore the `status` because it is not needed.

When the asynchronous operation is failed, `reason` is present and `value` is undefined. If the call is successful, `value` is present and `reason` is undefined. In this way we clearly know when the error is present.

`Note:` There is a common way to handle error in JavaScript is using `try...catch` I skip this because it is quiet well known pattern.

## Summery

Thanks for reading and I hope you learn something from this article. If  you have any question please let me know in the comments. I hope your code will be much better after using any of these pattern!