Reputation: 23
I'm trying to design a chain of promises with a catch error at the end in my node + express app. In the example below, if any one of the 'then' functions error out I'll have to work backwards to find which one from the error message. Is there an easier way to code the catch function?
new Promise(function(resolve, reject) {
resolve(groupId);
})
.then(sid => getGuestGroup2(sid))matching carts
.then(group =>getProducts(group))//add products
.then(result2 =>getPrices(result2))
.catch(error => { // (**)
console.log('Error on GET cart.js: '+error);
res.sendStatus(500);
});
Upvotes: 0
Views: 323
Reputation: 1790
The Promise
chaining is generic enough to not have 'which step failed' kind of information included out of the box. You could potentially try to decode it from stack trace, but in my opinion that's way more work than its worth. Here are few options you can employ to determine which step failed.
Set an extra property (as indicator) on the error object, which could be decoded in the catch block to determine which step in chain, the error originated from.
function predictibleErrors(promise, errorCode) {
return Promise.resolve(promise)
.catch(err => {
const newErr = new Error(err.message);
newErr.origErr = err;
newErr.errorCode = errorCode;
throw newErr;
});
}
Promise.resolve(groupId)
.then(sid => predictibleErrors(getGuestGroup2(sid), 'STEP_1')) // matching carts
.then(group => predictibleErrors(getProducts(group), 'STEP_2')) // add products
.then(result2 => predictibleErrors(getPrices(result2), 'STEP_3'))
.catch(error => { // (**)
console.log('Error on GET cart.js: '+error);
// Check error.errorCode here to know which step failed.
res.sendStatus(500);
});
Good old, catch after every step, and re-throw to skip subsequent steps.
function chainedErrorHandler(errCb) {
return (err) => {
if(err.handled) {
throw err;
}
errCb(err);
err.handled = true;
throw err;
};
}
Promise.resolve(groupId)
.then(sid => getGuestGroup2(sid)) // matching carts
.catch(chainedErrorHandler(err => {
console.log('step 1 failed');
}))
.then(group => getProducts(group)) // add products
.catch(chainedErrorHandler(err => {
console.log('step 2 failed');
}))
.then(result2 => getPrices(result2))
.catch(chainedErrorHandler(err => {
console.log('step 3 failed');
}))
.catch(error => {
// Some step has failed before. We don't know which one, here,
// but requisite processing for each failure could have been done
// in one of the previous catch blocks.
console.log('Error on GET cart.js: '+error);
res.sendStatus(500);
});
Please note that what we do in option two here, could also be done by the underlying methods directly. For eg. getGuestGroup2
or getProducts
could include an errorCode
or similar property on the error object that it throws. In this example we know step 1 or step 2 failed, but cannot know why. If the underlying methods were setting the same, they could include more accurate errorCodes with the knowledge of why the operation failed. I didn't take that route since the methods are not included in your sample and as far as I know they might not be in your control.
Upvotes: 1