Reputation: 2405
When there is a .then chain that includes a Promise.all such as the following example, do the errors get caught in the final .catch block for the parent .then chain or do they require their own error handling?
.then(([user, booking]) => {
const payment = { }
return Promise.all([
paymentService(payment),
Promise.resolve(user),
Promise.resolve(booking)
])
})
.then(([paid, user, booking]) => {
return Promise.all([
repo.makeBooking(user, booking),
Promise.resolve(paid),
Promise.resolve(user)
])
})
.catch((err) => {
//Error handling here
})
Upvotes: 0
Views: 758
Reputation: 5267
As you are returning a promise inside each .then()
, the errors are chained to the main flow, so in your example, the .catch
method will catch all errors.
Consider this example:
Promise.resolve(1)
.then((n) => {
return Promise.all([
Promise.resolve(`a-${n}`),
Promise.reject(Error('Failed in Promise.all')), // comment for success
]);
})
.then(([a, b]) => {
const msg = `Responses: [${a}, ${b}]`;
console.log(msg);
return msg;
})
.catch((error) => { throw error; });
Here the inner Promise.all()
has a reject that is caught by the parent flow.
Read some about chaining promises here: #2 Nested Promises
Upvotes: 1
Reputation: 8284
Simply put, .catch()
gets the value of a promise that is rejected.
Promise.prototype.catch(myHandler)
is the same thing as calling Promise.prototype.then(undefined, myHandler)
. So it
For promises that are chained with .then()
, what that means is that if the previous promise fails, then the subsequent rejected callback is called.
So if you have a the following code:
Promise.resolve().then((resolve, reject) => {
console.log('this is the first promise');
reject();
}).then(() => {
console.log('this is the second promise');
reject();
}).catch((value) => {
console.log('this is the third promise')
});
The output is:
this is the first promise
this is the third promise
The reason for that is follows: Promise.resolve() creates a promise. Let's number that as promise #1.
Note that .then
returns a new promise equal to the return of the inner promise. So by calling .then()
on line 1, we create promise #2. The second .then()
call creates promise #3.
Okay. Now that's set up, Promise #1 is already resolved, so it calls into the success case. That's why 'this is the first promise' prints. We then reject promise #2 inside the handler.
Promise #2 has one handler on it (with the body 'this is the second promise'). Since Promise #2 is rejected, this handler does not run. ** The way chained promises works means that this also causes Promise #3 to be rejected **. Therefore when we get to the catch()
handler, it runs the this is the third promise
example.
You can read more here for more examples: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
Upvotes: 1
Reputation: 3627
Yes, they are caught by the last (in your example) catch()
.
You could also insert another catch()
just after the then()
with Promise.all()
, and in that case both catch()-es
would be called. The only catch with that is that you would have to manually "rethrow" the error from the first catch()
:
.then(([user, booking]) => {
const payment = { }
return Promise.all([
paymentService(payment),
Promise.resolve(user),
Promise.resolve(booking)
])
})
.catch((error) => {
// Error handling logic...
// Rethrow the error to allow the second catch to... catch it
throw error;
})
.then(([paid, user, booking]) => {
return Promise.all([
repo.makeBooking(user, booking),
Promise.resolve(paid),
Promise.resolve(user)
])
})
.catch((err) => {
//Error handling here
})
Upvotes: 1