The promise's .then() method accepts an error callback as second param

This article was published on Jun 17, 2021

After years writing promises, today I learned that we can pass a callback to be called "on rejection" as a second parameter to the .then() method:

const myPromise = () =>
  new Promise((resolve, reject) => {
    reject('something went wrong');
  });

myPromise()
  .then(console.log, (error) => {
    console.log('inside the then error callback', error);
  });

This can be useful when we want to chain multiple "then" and do something if it fails I can add a very specific handler that intercepts this error, do something and either allow to continue the flow (it goes to the next .then() on success) or re-throw:

const myPromise = () =>
  new Promise((resolve, reject) => {
    reject('Something went wrong');
  });

const firstThenHandlers = {
  onSuccess(){
    console.log('First then: success');
  },
  onError(err){
    console.log('First then: error', err);
  }
}

const secondThenHandlers = {
  onSuccess(){
    console.log('Second then: success');
  },
  onError(err){
    console.log('Second then: error', err);
  }
}

myPromise()
  .then(firstThenHandlers.onSuccess, firstThenHandlers.onError)
  //becase I'm not re-throwing the error, the error won't reach `.catch` method
  .then(secondThenHandlers.onSuccess, secondThenHandlers.onError)
  .catch((error) => {    // never reached
    console.log('Catch callback: ', error);
  });

The curious fact is that since I'm intercepting the error with this callback, whatever I return from the firstThenHandlers.onError, will be passed to secondThenHandlers.onSuccess, which can be the error itself or a fallback response.

The possibilities are many. I think it worth a blog post in the future about this.

Resources