/

Handling Promise Rejections: Best Practices

Handling Promise Rejections: Best Practices

Promises have greatly improved JavaScript in recent years, allowing us to handle asynchronous operations more efficiently. When working with functions that return promises, it’s important to know how to handle promise rejections. In this blog post, we’ll explore the best practices for handling promise rejections effectively.

Let’s start with a simple example using the Fetch API:

1
2
3
4
fetch('/data.json')
.then(response => {
console.log(response.status)
})

But what if an error occurs during the fetch() call? For example, if the network is unavailable or the request returns an error. In such cases, the promise will reject.

A promise consists of two main functions: resolve and reject. Inside the promise, if everything goes well, the resolve() function is called, passing any desired value:

1
2
3
const thePromise = new Promise((resolve, reject) => {
resolve('ok') //you can pass any value
})

However, if something goes wrong, the reject() function is called:

1
2
3
const thePromise = new Promise((resolve, reject) => {
reject('error message') //you can pass any value
})

To handle promise rejections, we use the catch() method of the promise:

1
2
3
4
thePromise
.catch(error => {
console.error(error)
})

It is crucial to always include a catch() method to avoid promises failing silently.

You can also chain catch() to a then() method:

1
2
3
4
5
6
7
thePromise
.then(response => {
console.log(response)
})
.catch(error => {
console.error(error)
})

In case you have a chain of promises, you can add multiple catch() methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const thePromise = new Promise((resolve, reject) => {
resolve({
doSomething: function() {
return new Promise((resolve, reject) => {
reject('error!') //you can pass any value
})
}
})
})

thePromise
.then(response => {
return response.doSomething()
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})

In this case, if thePromise is rejected, the execution jumps directly to the catch() method.

Although you can add the catch() method in the middle of two then() methods, it’s important to note that you won’t be able to break the chain when something bad happens. Additionally, the return value of catch() (which is undefined by default) will be passed to the following then(). Hence, it’s best practice to place catch() at the end of the chain and use it to handle all possible errors.

While error handling is better achieved with async/await in my opinion, there are situations where promises are necessary. By following these best practices, you can effectively handle promise rejections and ensure the smooth functioning of your JavaScript code.

tags: [“JavaScript Promises”, “Fetch API”, “async/await”, “error handling”]