如何在 Promise 中 return 响应客户端?

How to return response to client in the middle of Promise?

例如,

Comments.findOne({user: req.user.id}).exce()
.then(function(comment) {
  if(comment) {
    // how to make this return immediately and break the rest then?
    return res.json({error: 'Already commented'});
  } else {
    return Posts.findOne({postId: req.params.id}).exec();
  }
})
.then(function(post) {
  if(post) {
    var comment = new Comment({user: req.user.id, data: req.body.comment})
    return {post: post, comment: comment.save()};
  } else {
    return res.json({error: 'Post not exist'});
  }
})
.then(function(data) {
  post.comments.push(comment._id);
  return post.save();
});
.then(function(post) {
  return res.json({ok: 1})
})
.catch(function(e)) {
  return res.json(error: e);
});

这个承诺写对了吗? 这种承诺怎么写? Callbacks/Promises很头疼...

您使用的是 bluebird,它支持 cancellation。这是一个例子:

var Promise = require('bluebird');
// enable cancellation
Promise.config({
    cancellation: true
});

// store your promise chain
var myPromise = Promise.resolve().then(() => {
    return 'foo';
}).then((res) => {
    console.log(res);
    // call cancel on the chain when needed
    myPromise.cancel();
    return res;
}).then((res) => {
    // this will not be executed
    console.log(res + '2');
});

您只需要 throw 或 return 一个拒绝承诺来触发承诺中的错误处理,如本例所示:

Comments.findOne({user: req.user.id}).exce()
.then(function(comment) {
  if(comment) {
    // to bypass all the other .then() resolve handlers, either
    // throw an error here or return a rejected promise
    throw new Error(res.json({error: 'Already commented'}));
  } else {
    return Posts.findOne({postId: req.params.id}).exec();
  }
})

Promise 是 "throw safe",这意味着 .then() 将捕获抛出的任何异常并将其变成拒绝的 promise。这将绕过任何以下 .then() 解析处理程序,而是转到下一个 reject 处理程序或 .catch() 处理程序。


仅供参考,你应该小心你的代码,因为当你 .catch() 然后只是 return 时,它会将你的 promise 状态从 rejected 更改为 resolved 然后它看起来像一个成功的promise 当你真的有错误时,任何调用者都会认为一切都成功了。这是因为 promise 基础设施假设如果你 .catch() 一个错误并且 return 一个你有 "handled" 错误和状态的值现在已成功解决。要允许错误继续从 .catch() 传播到更高级别的调用者,您必须重新抛出或 return 一个被拒绝的承诺:

blah(...).then(...)
.catch(function(e)) {
     throw new Error(res.json(error: e));
});