我正确使用承诺吗?

时间:2015-05-19 13:34:35

标签: node.js promise q

我有以下功能(我使用Q承诺库):

confirmEmail: function(confirmationCode){
    var deferred = q.defer();

    User.find({
      where: {confirmation_code: confirmationCode}
    }).then(function(user){
      if(user){
        user.updateAttributes({
          confirmation_code : null,
          confirmed: true
        }).then(function() {
          deferred.resolve();
        });
      }else{
        deferred.reject(new Error('Invalid confirmation code'));
      }
    });

    return deferred.promise;
  }

我一直在阅读有关承诺的最佳做法,例如: What is the explicit promise construction antipattern and how do I avoid it? http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html

我是否已编写上述功能以使其符合这些惯例,还是有更好的方法?

2 个答案:

答案 0 :(得分:3)

在我看来,你可以改写你的方法:

confirmEmail : function(confirmationCode) {
  return User.find({
    where : { confirmation_code : confirmationCode }
  }).then(function(user) {
    if (! user) {
      throw new Error('Invalid confirmation code');
    }
    return user.updateAttributes({
      confirmation_code : null,
      confirmed         : true
    });
  });
}

User.find()user.updateAttributes()似乎都在返回承诺(我在您的代码中推断这一点),因此您可以轻松地使用它们创建承诺链。

但即使他们没有回复承诺,你也可能不需要q.defer(),如概述on this page you already mention“新手错误#4”)。请参阅Q.Promise

答案 1 :(得分:0)

使用Mongoose(尤其是版本4),本机支持promises,因此您不需要使用Q.此外,在Node.js 0.12+和io.js上有对Promises的natie支持,所以再次不需要!Q

这就是我编写方法的方法(使用本机Promise;如果仍然在节点0.10上,这里是polyfill

confirmEmail: function(confirmationCode){
    return new Promise(function(resolve, reject) {
        User.find({
            where: {confirmation_code: confirmationCode}
        })
        .then(function(user) {
            if(user){
                user.updateAttributes({
                    confirmation_code : null,
                    confirmed: true
                })
                .then(resolve, reject)
            }
            else {
                reject(new Error('Invalid confirmation code'))
            }
        }, reject)
    })
}

工作原理: 1. confirmEmail方法返回一个Promise。根据模式,承诺可以是resolve()'d或reject()'d 2.调用User.find。使用Mongoose,它会返回一个promise,因此您可以执行:then(callback, reject)。因此,如果User.find返回错误,则confirmEmail返回的Promise将被拒绝(“外部的”)。 3.如果User.find成功,我们继续。如果没有结果(if(user)为假),那么我们手动拒绝“外部承诺”,我们不做任何其他事情。 4.如果有用户,我们会调用user.updateAttributes,这也会返回一个承诺。我们因此调用then(resolve, reject),因此该承诺的结果将传递给“外部承诺”。

使用示例:

obj.confirmEmail(confirmationCode).
.then(function(user) {
    // Everything went fine
}, function(error) {
    // This is invoked if: User.find() failed, or if no result was obtained (with the error "Invalid confirmation code") or if user.updateAttributes failed
})