Search code examples
javascriptchaining

Javascript Promises Chaining Multiple Errors


How come that all my Resolved Callbacks are properly executed but only 1 Error Callback is being run ?

In the example here if longOperation(true) I get only one error, while when run with false I get the two resolved messages. In my understanding each .then returns a new promise which is in the error state for the second .then error callback registration

This example is written using Typescript !

function longOperation(error) {
  return new Promise < any > ((resolve, reject) => {
    if (error) {
      reject("Error")
    } else {
      setTimeout(function() {
        resolve(true)
      }, 1000)
    }

  })
}

let op = longOperation(true);

op
  .then(result => {
    console.log("Resolved #1")
  }, undefined)
  .then(result => {
    console.log("Resolved #2")
  }, undefined)
  .then(undefined, error => {
    console.log("Error1")
  })
  .then(undefined, error => {
    console.log("Error2")
  })


Solution

  • Promises can "recover".

    The error will propagate down the chain of ".then"s until it finds an error callback. When it does it will execute the error callback and pass the return value down to the next promise's resolve method.

    So only the next closest error callback to the promise will get executed.

    If you want to catch all possible errors along the chain just put your error callback at the end of the chain and all errors will be handled by it.

    In your code example you are actually creating 5 promises. The original one and 1 for each ".then". The 2nd and 3rd only have an onResolved method and the last two only have and onRejected method.

    This is how it will be executed:

    1st Promise(op): I just rejected. I see I have a deferred promise with no onRejected callback. So I'll just call it's reject method with the same value I rejected with.

    2nd Promise: The previous promise called my reject method and I also have a deferred promise with no onRejected callback. So I'll just call it's reject method with the same value I rejected with.

    3rd Promise: The previous promise called my reject method. I have a deferred promise too, but mine does have an onRejected callback. I,ll call the callback with the value I rejected with, and I'll call my deferred promise's resolve method with the callback's return value.

    4th Promise: The previous promise called my resolve method. I have a deferred promise, but it doesn't have an onResolved callback so I'll just call it's resolved method with the value I resolved with.

    5th Promise: The previous promise called my resolve method. I resolved and did nothing more because I have no deferred promise.