Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chaining promises with then and catch

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?

like image 568
Alexandre Kirszenberg Avatar asked Jul 07 '14 20:07

Alexandre Kirszenberg


People also ask

How do you use then catch in promise?

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.

Can promise be chained?

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 ).

What is chaining in promises?

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.


2 Answers

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); 
like image 188
Bergi Avatar answered Sep 22 '22 12:09

Bergi


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.

like image 26
Mercury Avatar answered Sep 23 '22 12:09

Mercury