I'm using the bluebird Promise library. I'd like to chain promises and catch specific promises errors. Here's what I'm doing :
getSession(sessionId) .catch(function (err) { next(new Error('session not found')); }) .then(function (session) { return getUser(session.user_id); }) .catch(function (err) { next(new Error('user not found')); }) .then(function (user) { req.user = user; next(); });
But if an error is thrown by getSession
, the two catch
are called, as well as the second then
. I'd like to stop the error propagation at the first catch
, so that the second catch
is only called when getUser
throws, and the second then
when getUser
succeeds. What do?
In summary: then : when a promise is successful, you can then use the resolved data. catch : when a promise fails, you catch the error, and do something with the error information. finally : when a promise settles (fails or passes), you can finally do something.
Introduction to the JavaScript promise chainingThe callback passed to the then() method executes once the promise is resolved. In the callback, we show the result of the promise and return a new value multiplied by two ( result*2 ).
Promise chaining: Promise chaining is a syntax that allows you to chain together multiple asynchronous tasks in a specific order. This is great for complex code where one asynchronous task needs to be performed after the completion of a different asynchronous task.
The promise that is returned by the .catch
method will still be resolved with the result of the callback, it doesn't just stop the propagation of the chain. You will either need to branch the chain:
var session = getSession(sessionId); session.catch(function (err) { next(new Error('session not found')); }); var user = session.get("user_id").then(getUser); user.catch(function (err) { next(new Error('user not found')); }) user.then(function (user) { req.user = user; next(); });
or use the second callback to then
:
getSession(sessionId).then(function(session) { getUser(session.user_id).then(function (user) { req.user = user; next(); }, function (err) { next(new Error('user not found')); }); }, function (err) { next(new Error('session not found')); });
Alternatively, the better way would to just propagate the errors through the chain, and call next
only in the very end:
getSession(sessionId).catch(function (err) { throw new Error('session not found')); }).then(function(session) { return getUser(session.user_id).catch(function (err) { throw new Error('user not found')); }) }).then(function (user) { req.user = user; return null; }).then(next, next);
Since you're using bluebird for promises, you actually don't need a catch statement after every function. You can chain all your thens together, and then close the whole thing off with a single catch. Something like this:
getSession(sessionId) .then(function (session) { return getUser(session.user_id); }) .then(function (user) { req.user = user; next(); }) .catch(function(error){ /* potentially some code for generating an error specific message here */ next(error); });
Assuming the error messages tell you what the error is, it's still possible to send an error specific message like 'session not found' or 'user not found', but you'll just have to look into the error message to see what it gives you.
Note: I'm sure you probably have a reason for calling next regardless if there's an error or not, but it might be useful to throw in a console.error(error) in the case that you get an error. Alternatively, you could use some other error handling function, whether it's a console.error, or res.send(404), or something of the like.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With