Chained Promises Not Passing on Rejection

Chained promises not passing on rejection

To me, this result doesn't make sense. By attaching to this promise chain, each then is implying the intent that it will be dependant upon the successful resolution of d1 and a result being passed down the chain

No. What you are describing is not a chain, but just attaching all the callbacks to d1. Yet, if you want to chain something with then, the result for promise2 is dependent on the resolution of promise1 and how the then callbacks handled it.

The docs state:

Returns a new promise for the result of the callback(s).

The .then method is usually looked upon in terms of the Promises/A specification (or the even stricter Promsises/A+ one). That means the callbacks shell return promises which will be assimilated to become the resolution of promise2, and if there is no success/error handler the respective result will in case be passed directly to promise2 - so you can simply omit the handler to propagate the error.

Yet, if the error is handled, the resulting promise2 is seen as fixed and will be fulfilled with that value. If you don't want that, you would have to re-throw the error, just like in a try-catch clause. Alternatively you can return a (to-be-)rejected promise from the handler. Not sure what Dojo way to reject is, but:

var d1 = d();

var promise1 = d1.promise.then(
function(wins) { console.log('promise1 resolved'); return wins;},
function(err) { console.log('promise1 rejected'); throw err;});
var promise2 = promise1.then(
function(wins) { console.log('promise2 resolved'); return wins;},
function(err) { console.log('promise2 rejected'); throw err;});
var promise3 = promise2.then(
function(wins) { console.log('promise3 resolved'); return wins;},
function(err) { console.log('promise3 rejected'); throw err;});
d1.reject(new Error());

How is Bob able to get a blue widget from Ginger when didn't get any herself?

He should not be able. If there are no error handlers, he will just perceive the message (((from the distributor) from John) from Ginger) that there are no widgets left. Yet, if Ginger sets up an error handler for that case, she still might fulfill her promise to give Bob a widget by giving him a green one from her own shack if there are no blue ones left at John or his distributor.

To translate your error callbacks into the metapher, return err from the handler would just be like saying "if there are no widgets left, just give him the note that there are no ones left - it's as good as the desired widget".

In the database situation, if the db.query failed, it would call the err function of the first then

…which would mean that the error is handled there. If you don't do that, just omit the error callback. Btw, your success callbacks don't return the promises they are creating, so they seem to be quite useless. Correct would be:

var promise = db.query({parent_id: value});
promise.then(function(query_result) {
var first_value = {
parent_id: query_result[0].parent_id
}
var promise = db.put(first_value);
return promise.then(function(first_value_result) {
var second_value = {
reference_to_first_value_id: first_value_result.id
}
var promise = db.put(second_value);
return promise.then(function(second_value_result) {
return values_successfully_entered();
});
});
});

or, since you don't need the closures to access result values from previous callbacks, even:

db.query({parent_id: value}).then(function(query_result) {
return db.put({
parent_id: query_result[0].parent_id
});
}).then(function(first_value_result) {
return db.put({
reference_to_first_value_id: first_value_result.id
});
}.then(values_successfully_entered);

Angular 2 chained Promise and passing on reject

See https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch

You need to throw an exception in the catch handler for example to reject the second chain.

// First chain, no problem
promise.then(data => {
console.log('Success callback', data); // This will not be called
}).catch(err => {
console.log('Error callback', err); // This will NOT be called
throw "zonk";
})

Why is onRejected not called following Promise.all() where Promise.reject() included in array passed to Promise.all()?

What you've really done here is something like this:

https://jsfiddle.net/9gprLc7q/5/

var notRejectedPromise = 
Promise.reject("b")
.then((resolved) => resolved, (err) => err)

var promises = [Promise.resolve("a"), notRejectedPromise];

Promise.all(promises)
.then(function(complete) {
console.log("all promises after .map()", complete)
}, function(err) {
console.log("err", err)
})

But deciding to handle the err portion by returning whatever err was, you returned a string. This is not a reason for rejection.

To actually cause the Promise.all() to reject you need an error to occur in either the resolved or rejected portion of .then

Given this, if you return a rejected promise, it will reject:

https://jsfiddle.net/9gprLc7q/3/

console.log(err)

to

return Promise.reject(err)

Alternatively you can throw an error: https://jsfiddle.net/9gprLc7q/2/

console.log(err)

to

throw new Error(err)

Why do JavaScript promises chain rejections into resolved promises?

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!");
});

Chaining promises but continue with the next promise when one fails (and log the rejection)

You can handle the rejection within the reduce callback;

funcs.reduce((prev, cur) => prev.then(cur).catch(log), starting_promise)

Or you could pre-process the array of functions:

funcs.map(f => v => f(v).catch(log)) 
.reduce((prev, cur) => prev.then(cur), starting_promise)

In either case, the point is that the catch puts the promise back on the success track, as it were (unless you throw inside the catch handler).

Note that whatever the catch handler returns becomes the input value to the next function in the promise chain. If you want the rejection reason to become the input, then return it from the catch handler:

function log(reason) {
console.log("rejected with reason", reason, "continuing...");
return reason;
}

From a comment:

How do I use the cur reference in the catch -> log function?

Instead of just passing log to the catch, pass a function which calls log with both the reason and the function:

funcs.reduce(
(prev, cur) => prev.then(cur).catch(reason => log(reason, cur)),
starting_promise)

function log(reason, func) {
console.log("rejected with reason", reason, "in function", func, "continuing...");
return reason;
}

Why catch at the end of promise chain is not catching all the errors?

Looks like the issue is that isUsed is being executed immediately rather than after inBlacklist resolves, so your .then() is being given a Promise object rather than a callback function. It's just like if you wrote a(b(c));, b is executed first and then the return value is passed to a.

Instead, you want to pass to .then a callback function that executes the next function, so try using arrow functions inside the thens, like so:

inBlacklist(address)
.then(() => isUsed(payments))
.then(() => isProcessed(ref_num))
.then(() => validateType(type))
.catch((err) => {
console.log(err);
return res.status(400).send({ message: err.message });
});

Can a chain be stopped without sending an error message to the console?

Both .then(success, error) callbacks return promises.

That is:

Promise.reject()

.then(function () {
// won't be called, as above promise is rejected
}, function () {
// will be called, and returns a resolved promise by default;
// if you want the next error callback to be called,
// you need to return a rejected promise or to throw an error
})

.then(function () {
// 1: called if above .then returns a resolved promise
}, function () {
// 2: called if above .then returns a rejected promise or throws an error
})

Where is the executor code for a chained promise in javascript?

Essentially each promise that's created from each then() gets resolved/rejected automatically based on the return status of the callback function. If you reject the promise by either returning a rejected promise (return Promise.reject(err)), throwing an error, or if an error occurs, it will call the 2nd callback (error handler) of the next .then(). So, if you want to chain promises and keep calling the error handler, you need to keep rejecting the promise. Returning a valid value will resolve the first promise, which is why your "success" callback gets called in the 2nd .then()

You can also manually return a Promise() from .then() and have it immediately resolve/reject based on the logic.. promises don't have to have async logic inside of them

function testPromise(isSuccess) {
new Promise((resolve, reject) => {
setTimeout(() => {
if (isSuccess) { resolve("Success!"); }
else { reject(new Error("NOT SUCCESS!")); }
}, 1000)
}).then((res) => {
console.log("Inside 1st .then success:", res);
return res;
}, (err) => {
console.log("Inside 1st .then error:", err.message);
// return Promise.reject(err); // this also works to reach next error handler
// throw err; // this also works to reach next error handler
return new Promise((resolve, reject) => reject(err));
}).then((res) => {
console.log("Inside 2nd .then success:", res);
}, (err) => {
console.log("Inside 2nd .then error:", err.message);
})
}

testPromise(true);
testPromise(false);


Related Topics



Leave a reply



Submit