I am trying to chain promises so that the chain will break if one promise is rejected. I followed the leads of a previous SO question and tried to apply it to native promises, but I think I am misunderstanding the way things work.
Here is how I have rewritten the code:
Promise.resolve()
.then(function() {
return step(1)
.then(null, function() {
stepError(1);
});
})
.then(function() {
return step(2)
.then(null, function() {
stepError(2);
});
})
.then(function() {
return step(3)
.then(null, function() {
stepError(3);
});
});
function step(n) {
console.log('Step '+n);
return (n === 2) ? Promise.reject(n) : Promise.resolve(n);
}
function stepError(n) {
console.log('Error '+n);
return Promise.reject(n);
}
The output of the above code is:
Step 1
Step 2
Error 2
Step 3
[UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): 2]
In my understanding, step 2 should break the chain and step 3 should not be executed. When step(2) returns a rejected promise, stepError(2) is executed as expected. But since it returns Promise.reject(2), the function in the next then should not be executed, and since there is not catch in the end, the rejected promise of step 2 seems - as expected - to be forwarded until it exits the chain because it didn't find any handler.
What am I missing here ?
Here is a JSFiddle to play with: https://jsfiddle.net/6p4t9xyk/
In my understanding, step 2 should break the chain...
It would, but you've accidentally converted that rejection into a resolution.
The key thing about promises is that every call to then
creates a new promise which is resolved/rejected based on what the then
callback(s) do, and the callback processing a rejection converts that rejection into a resolution unless it intentionally does otherwise.
So here:
return step(2)
.then(null, function() { // This handler converts the
stepError(2); // rejection into a resolution
}); // with the value `undefined`
That's so that you can have error handlers that compensate for the error.
Since stepError
returns a rejection, you could continue the rejection by just adding a return
:
return step(2)
.then(null, function() {
return stepError(2); // Added `return`
});
...or alternately, remove that handler entirely:
return step(2);
...or you could throw
in the callback, which is automatically turned into a rejection.
The unhandled rejection warning is caused by the fact nothing consumes the rejection from stepError
.
Here's an example returning the result of stepError
:
Promise.resolve()
.then(function() {
return step(1)
.then(null, function() {
return stepError(1); // Added `return`
});
})
.then(function() {
return step(2)
.then(null, function() {
return stepError(2); // Added `return`
});
})
.then(function() {
return step(3)
.then(null, function() {
return stepError(3); // Added `return`
});
});
function step(n) {
console.log('Step '+n);
return (n === 2) ? Promise.reject(n) : Promise.resolve(n);
}
function stepError(n) {
console.log('Error '+n);
return Promise.reject(n);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With