我是否正确使用了承诺?

Am I using promises correctly?

我有以下功能(我正在使用 Q promise 库):

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

我写的上面的函数是否符合这些做法,或者有更好的方法吗?

在我看来,您可以将方法重写为:

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() 似乎都在返回 promises(我是从你的代码中推断出来的),所以你可以很容易地用它们创建一个 promise 链。

但即使他们没有返回承诺,您也可能不需要 q.defer(),如 on this page you already mention ("Rookie mistake #4"). See Q.Promise 所述。

使用 Mongoose(尤其是从版本 4 开始),原生支持 promises,因此您不需要使用 Q。此外,在 Node.js 0.12+ 和 io.js 上,对 Promises 提供了 natie 支持, 所以再次不需要 Q!

这就是我编写该方法的方式(使用本机 Promise;这里 polyfill 如果仍在 Node 0.10 上)

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 方法returns 一个Promise。根据模式,promise 可以是 resolve()'d 或 reject()'d 2. User.find 被调用。使用 Mongoose,returns 一个承诺,因此您可以:then(callback, reject)。因此,如果 User.find returns 出错,则 confirmEmail 返回的 Promise 将被拒绝("outer one")。 3. 如果 User.find 成功,我们继续。如果没有结果(if(user) 为假),那么我们手动拒绝 "outer promise" 并且我们不做任何其他事情。 4. 如果有用户,我们调用 user.updateAttributes,这也是 returns 一个承诺。因此,我们正在调用 then(resolve, reject),因此该承诺的结果将传递给 "outer promise"。

使用示例:

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