Reputation: 1545
I'm new to promises, but as I understand it, .catch
usually belongs at the end of a chain of promises:
promiseFunc()
.then( ... )
.then( ... )
.catch( // catch any errors along the chain )
What if the promises are split in between functions? Do I catch at the end of every function?
func1 () {
promiseFunc1()
.then((result) => {
promiseFunc2()
)
// should I .catch here?
}
func2 () {
func1()
.then((result) => {
// do stuff
})
.catch(console.log.bind(console)); // this also catches errors from func1
}
Maybe this is a symptom of another error (in which I'd love to hear if I'm doing this wrong), but when I try catching at the end of func1, I end up reaching the .then
block of func2, with result = undefined
. After deleting the catch in func1
, it works -- but it feels wrong that func1 should expect any functions calling it to catch its errors.
Upvotes: 1
Views: 96
Reputation: 707386
.catch()
works very much like try/catch
. You should .catch()
wherever you want or need to handle the error and either log something or change the course of the chain.
If all you want is for the promise chain to abort when an error occurs, then you can just put one .catch()
at the very end of the chain and deal with the error there.
If, on the other hand, you have some sub-part of the chain that, if it has a rejection you want to do something different and allow the chain to continue or to take a different path, then you need to .catch()
at that level where you want to influence things if there's an error.
All or Nothing Catch at the End
So, let's say you have four functions that all return promises.
If you do this:
a().then(b).then(c).then(d).then(finalResult => {
// final result here
}).catch(err => {
// deal with error here
});
Then, if anyone of your four promises rejects, then the rest of the chain will abort and it will skip to your one .catch()
. For some operations, this is the desired behavior. If you intend to fetch some data from an external server, use that data to then fetch some other data from another external server and then write that data to disk, the whole process is pretty much all or nothing. If any of the earlier steps fails, there's nothing else you can do as the whole operation has failed, you may as well just use one .catch()
at the end and report that error.
Intervening Catch to Change the Behavior Mid-Chain upon Error
On, the other hand suppose you have a situation were you want to fetch some data from an external server, but if that server is down, then you want to fetch the data from an alternate server. In that case, you want to catch the error from the first fetch and try something else. So, you'd use a .catch()
on the very first step and attempt something different:
fetch1().catch(fetch2).then(b).then(c).then(finalResult => {
// final result here
}).catch(err => {
// deal with error here
});
Logging and Rethrow
When building sub-systems that others will use, it is often useful to log certain types of errors. So, even the whole promise chain might be all or nothing, you still may want to log an error earlier in the chain and then rethrow the error so that the chain continues in the rejected state:
function someFuncOthersUse() {
return a().then(b).then(c).catch(err => {
// you want your own logging any time a or b or c rejects
console.log("Error on fetchB", err);
throw err;
});
}
The caller will then be doing:
someFuncOthersUse().then(finalResult => {
// final result here
}).catch(err => {
// deal with error here
});
Upvotes: 2