I have the following function that returns a Promise:
function someFn() {
// Making use of Bluebird's Promise.all()
return Promise.all([promise1, promise2]).then(function(results) {
results.forEach(function(result) {
return promiseReturningFn(); // Returns a Promise
});
}).catch(function(err) {
console.log(err);
});
}
I have two questions regarding this piece of code:
forEach()
iteration's promiseReturningFn()
rejects, will the rejection be caught by the catch()
statement?promiseReturningFn()
rejects, will the iteration stop, meaning that the callback will not be called for the second element in the results array? If this is true, will control flow be passed to the catch()
statement after this failure? On your two questions:
- In a scenario where any of the forEach() iteration's promiseReturningFn() rejects, will the rejection be caught by the catch() statement?
No, because you do not return
a promise in the then
callback, but in the forEach
callback, and the latter has no effect -- such a return value is lost in oblivion.
- If the first iteration's promiseReturningFn() rejects, will the iteration stop, meaning that the callback will not be called for the second element in the results array? If this is true, will control flow be passed to the catch() statement after this failure?
No, the iteration will not stop. You would not even know about a rejection synchronously, as this info only becomes available asynchronously (ignoring for a moment that bluebird
allows synchronous inspection).
Here is probably how you should code it, assuming you allow the promiseReturningFn
to already be executed on a resolved promise when the other one is not yet resolved:
function someFn() {
// Making use of Bluebird's Promise.all()
return Promise.all(
[promise1, promise2].map(p => p.then(promiseReturningFn))
}).catch(function(err) {
console.log(err);
});
}
Or, if you really need the array of promises to all resolve before you start executing promiseReturningFn
for them, then do this:
function someFn() {
// Making use of Bluebird's Promise.all()
return Promise.all([promise1, promise2]).then(results => {
return Promise.all(results.map(promiseReturningFn));
}).catch(function(err) {
console.log(err);
});
}
In either case the answers to your two questions are now:
Yes, if either inner promise rejects, the catch
callback will be executed.
No, the iteration will not stop, since the result of a promise is only known asynchronously, so by that time the loop (map
) will already have executed completely.
To make the answer "Yes" to the second question and stop calls being made to promiseReturningFn
when a previous returned promise rejects, you must serialise them, waiting for one promise to fulfil before invoking promiseReturningFn
again:
function someFn() {
// Making use of Bluebird's Promise.all()
return Promise.all([promise1, promise2]).then(results => {
return (function loop(i, p) {
return i >= results.length ? p
: p.then(_ => loop(i+1, promiseReturningFn(result[i])));
})(0, Promise.resolve());
}).catch(function(err) {
console.log(err);
});
}