Reputation: 54771
I'm wondering why rejections are chained as resolved with ES6 promises?
Here's an example:
let p = Promise.reject().then(function () {
return 'one';
}, function() {
return 'two';
});
p.then(function (value) {
// I do not expect this to be executed, since it was not resolved.
console.log(value);
});
The above outputs "two" to the console.
https://jsfiddle.net/pscb88xg/1/
Why does the chaining of a promise mutate a rejection into a successful resolve?
Edit: I want to clarify that the question has practical application.
What if you want to convert data from A to B using chaining.
p.then(function (A) {
return new B(A);
});
The above mutates rejections into resolved values. Even if no reject callback is used.
For example;
let p = Promise.reject('error').then(function (A) {
return new B(A);
});
// some code elsewhere
p.then(function (B) {
console.log('success!');
});
In the above example. The value B is not B but the error, and it was resolved successfully later in the chain.
Is this normal?
Edit: I understand my confusion now. I was extracting HTTP header values in rejections like this.
let p = myHttpService.get(...).then(function() {
//....
}, function(response) {
// get headers
});
The above was chaining my promises to a resolved value, and I didn't understand why. I can fix my code with the following.
let p = myHttpService.get(...).then(function() {
//....
}, function(response) {
// get headers
return Promise.reject(response);
});
Upvotes: 2
Views: 744
Reputation: 31600
It's meant to allow you to gracefully recover from an error in a promise chain.
An example might be the 304 Not Modified response from the server. If you were to use a promise based library to do an http request any response that's not 2XX will be considered a failure and the promise will be rejected. From an application's point of view however 304 might just as good as a 200 and you'd like to continue as normal.
Upvotes: 1
Reputation: 6652
This is the same behavior as AngularJS's $q
provider.
The mutation occurs because in your rejection handler, you are returning a value and not a rejected promise. If you were to instead, pass a rejected promise, it would behave how you were expecting:
let p = Promise.reject().then(function () {
return 'one';
}, function() {
return Promise.reject('two');
});
p.then(function (value) {
// I do not expect this to be executed, since it was not resolved.
console.log(value);
}, function() {
console.log("Rejected, baby!");
});
Upvotes: 0
Reputation: 92521
MDN documentation for Promise.prototype.then
says:
After the invocation of the handler function [the function passed to
then()
], the promise returned bythen
gets resolved with the returned value as its value.
Upvotes: 1
Reputation: 141827
After handling an error you usually want your code to continue, similar to how code after a catch block runs like normal, whereas uncaught exceptions abort.
If you want to abort instead then don't handle the error until the end of the chain:
let p = Promise.reject().then(function () {
return 'one';
});
p.then(function (value) {
// This won't run, because the rejection hasn't been handled yet
console.log(value);
}, function() {
return console.log( 'there was a problem' );
}).then(function ( ) {
// This will run because the rejection has been dealt with already.
console.log( 'Moving on');
});
Upvotes: 1