Yizhe
Yizhe

Reputation: 95

Will reject() skip all following then() in Promise

I am always curious that if a Promise is rejected at any position, will the following then() still be executed? Take the codes below as an example:

Promise.reject('reJECTed')
.then(() => {
    console.log('before resolve()');
    return Promise.resolve('reSOLVed');
})
.then((msg) => {
    console.log('reSOLVed inside 1st then()');
    console.log(msg);
}, (msg) => {
    console.log('reJECTed inside 1st then()');
    console.log(msg);
})
.then((msg) => {
    console.log('reSOLVing inside 2nd then()');
    console.log(msg);
}, (msg) => {
    console.log('reJECTing inside 2nd then()');
    console.log(msg);
})
.catch((msg) => {
    console.log('reJECTed in catch()');
    console.log(msg);
});

It will print

reJECTed inside 1st then()
reJECTed
reSOLVing inside 2nd then()
undefined

on the console, which means the resolve() in second then() and the last catch() were not executed. Does that mean when met reject(), any following resolve()s inside a then() is totally skipped until the rejection is caught?

Thanks for any explanation!

Upvotes: 5

Views: 1460

Answers (3)

jfriend00
jfriend00

Reputation: 707996

Does that mean when met reject(), any following resolve()s inside a then() is totally skipped until the rejection is caught?

Yes. When a promise rejects, all resolve handlers in the chain are skipped up until some reject handler handles the rejection and changes the promise chain back to fulfilled.

And, in case you didn't realize, the 2nd argument to a .then() handler is a reject handler (pretty much the same as a .catch() handler).

But, keep in mind that if you have a reject handler and it does not throw or return a rejected promise, then the chain becomes fulfilled again since you have "handled" the rejection. It's exactly like with try/catch. If you catch and don't rethrow, then the exception is handled and normal execution continues after that.

So, in your reject handler that outputs reJECTed inside 1st then(), you are not returning anything so at that point the promise chain becomes fulfilled. The rejection has been "handled" at that point and the promise chain now switches to the fulfilled state.

Here's some annotation on your code:

Promise.reject('reJECTed')
.then(() => {
    // this fulfilled handler is skipped because the promise chain is rejected here
    console.log('before resolve()');
    return Promise.resolve('reSOLVed');
})
.then((msg) => {
    // this fulfilled handler is skipped because the promise chain is rejected here
    console.log('reSOLVed inside 1st then()');
    console.log(msg);
}, (msg) => {
    // this reject handler is called because the promise chain is rejected here
    console.log('reJECTed inside 1st then()');
    console.log(msg);
    // because this does not rethrow or return a rejected promise
    // the promise chain switches to fulfilled
})
.then((msg) => {
    // this fulfilled handler is called because the promise chain is fulfilled now
    console.log('reSOLVing inside 2nd then()');
    console.log(msg);
}, (msg) => {
    // this reject handler is not called because the promise chain is fulfilled now
    console.log('reJECTing inside 2nd then()');
    console.log(msg);
})
.catch((msg) => {
    // this reject handler is not called because the promise chain is fulfilled now
    console.log('reJECTed in catch()');
    console.log(msg);
});

Let me offer another example to show how a promise chain can switch states:

Promise.reject("Hello").then(val => {
    console.log("1: I am not called");
}).catch(err => {
    console.log("2: I am rejected");
    // rethrow to keep promise chain rejected
    throw err;
}).catch(err => {
    console.log("3: I am still rejected");
    // return normal value, promise chain switches to fulfilled
    return "GoodBye";
}).then(val => {
    console.log("4: Now back to fulfilled state");
}).catch(err => {
    console.log("5: Not called");
});

Upvotes: 7

Lyubomir
Lyubomir

Reputation: 20037

Yes, this is described in Scenario B


Promise.reject will result in a rejected promise, which means

Scenario A

results in unhandled promise, if no then or catch

Scenario B

it will fallback to the first catch or error hook specified by then

Promise.reject()
      .then(
       () => {},
       () => { console.log ('Im called') } // goes here
      )

    Promise.reject()
      .catch(() => { console.log('Im called as well') }) // or here

Remember that then and catch return either

  • A promise which resolved to their return value
  • Or throw an error / rejected promise

Now everything goes carries on again from Scenario A or B, for instance

Promise.reject()
      .catch(() => { return 5; }) // returns promise that resolves to 5, 
      .then(
        res => console.log('See, Im not rejected and resolve to', 5),
        () => {}
      );

Upvotes: 1

holi-java
holi-java

Reputation: 30696

Promise.then() method provide two callbacks parameters.the first one invoked when resolved,and the second invoked when rejected.so your code above is called Promise.then(resolved,rejected) with two callbacks form;

Upvotes: 0

Related Questions