6

I got confusion about Promise chain in ES6.

function taskA() {
  console.log("Task A");
  throw new Error("throw Error @ Task A")
}

function taskB() {
  console.log("Task B");
}

function onRejected(error) {
  console.log(error);// => "throw Error @ Task A" 
}
  
function finalTask() { 
  console.log("Final Task");
}

var promise = Promise.resolve(); 
promise
.then(taskA) 
.then(taskB) 
.catch(onRejected) 
.then(finalTask);

What I'm lost here is why finalTask will be called? Does the catch() chain returns a resolved Promise?

JasmineOT
  • 1,978
  • 2
  • 20
  • 30
  • possible duplicate of [Chained promises not passing on rejection](http://stackoverflow.com/q/16371129/1048572) – Bergi Sep 27 '15 at 12:38

1 Answers1

14

When you provide a .catch() handler or the second argument for .then(), the rejected promise has been "handled". By default, when you provide such a reject handler, the promise system will assume that the rejection has been handled and the chain should continue.

If you don't want the chain to continue, then from the reject handler, you can either return a rejected promise or throw an error. That will then stop that chain up until another reject handler in the chain.

So, here are the possibilities in a chain like you show:

1) There is no reject handler in the chain

The chain is stopped entirely and no further .then() fulfill handlers are executed.

2) There is a reject handler in the chain that either returns nothing or returns a regular value or a fulfilled promise or a promise that eventually fulfills.

This is what your code currently shows. The reject is considered handled and the promise state of the chain changes to a fulfilled promise so subsequent fulfillment handlers in the chain are called.

3) There is a reject handler in the chain that either returns a rejected promise or throws an error

Returning the rejected promise (or a promise that rejects in the future) or throwing a new error (which gets turned into rejected promise) will stop further processing of the chain up until the next error handler.

So, if you changed your onRejected() handler to this:

function onRejected(error) {
     console.log(error);
     throw error;    // rethrow error to stop the rest of the chain
}

Then, your promise chain would stop there.


It's important to understand why it works this way. This allows you to handle an error in the middle of the promise chain and the code handling the error gets to decide whether the chain continues or not based on what it returns or throws. If it returns nothing or a normal value or a fulfilled promise, then processing of the chain continues - the error has been handled - no need to stop further processing.

But, if the error is more serious than that and processing should not continue, then the reject handler can either throw the same error or throw a different error or return a rejected promise and the chain will skip any fulfill handlers up until the next reject handler in the chain.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 2
    It's quite analogous to `catch` in synchronous `try {} catch (e) {}` in this way (error is handled unless rethrown). – jib Sep 28 '15 at 01:15