Skip to content

How to handle promise rejections

New Course Coming Soon:

Get Really Good at Git

Promises are one of the best things that happened to JavaScript in the past few years.

When we invoke a function that returns a promise, we chain the then() method of the promise to run a function when the promise resolves.

Here’s an example using the Fetch API:

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

What if there is an error during the fetch() call? Perhaps the network is unavailable. Or the network request returns an error.

The promise will reject. A promise will look something like this:

const thePromise = new Promise((resolve, reject) => {

})

Inside the promise we are passed 2 parameters, 2 functions. Inside the body, if all goes find, the resolve() function is called:

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

If something bad happens, the reject() function is called:

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

If something goes bad, we must handle the promise rejection. We do so using the catch() method of the promise:

thePromise
  .catch(error => {
    console.error(error)
  })

We must always add a catch(), otherwise promises will silently fail.

We can chain catch() to a then() method:

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

Or even multiple ones, if you have a chain of promises:

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.

You can add the catch() method in the middle of two then() methods, but you will not be able to break the chain when something bad happens. And the return value of catch() (which will have the undefined value if not specified) will be passed to the following then().

It’s best, in my opinion, to leave catch() at the end of the chain, and use it to handle all possible errors.

Error handling in my opinion is best in async/await, but sometimes we can’t avoid using promises, so that’s how you can do it.

Are you intimidated by Git? Can’t figure out merge vs rebase? Are you afraid of screwing up something any time you have to do something in Git? Do you rely on ChatGPT or random people’s answer on StackOverflow to fix your problems? Your coworkers are tired of explaining Git to you all the time? Git is something we all need to use, but few of us really master it. I created this course to improve your Git (and GitHub) knowledge at a radical level. A course that helps you feel less frustrated with Git. Launching May 21, 2024. Join the waiting list!
→ Get my JavaScript Beginner's Handbook
→ Read my JavaScript Tutorials on The Valley of Code
→ Read my TypeScript Tutorial on The Valley of Code

Here is how can I help you: