2015-05-19 181 views
0

我有以下功能(我使用的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

我写了上面的函数,以便它符合这些做法,还是有更好的方法?

+1

只是想知道 - 什么是这里的例子不清? http://stackoverflow.com/questions/23803743/what-is-the-deferred-antipattern-and-how-do-i-avoid-it –

回答

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

+2

s/can/should/:-) – Bergi

+0

我不确定控制流程。 confirmEmail方法返回User.find的承诺,所以如果你调用'then()',你会得到这个承诺的结果,而不是'user.updateAttributes'一个 – Qualcuno

+0

@Qualcuno:不, 'confirmMail'返回在User.find()'promise上调用'.then()'*的*结果,所以它是一个以'user.updateAttribute()'的结果解决的promise。 – Bergi

0

使用Mongoose(特别是从版本4),承诺是本地支持的,所以你不需要使用Q.另外,在Node.js 0.12+和io.js上有对Promise的natie支持,所以再次没有必要为Q!

这是我会怎么写的方法(使用原生的承诺;如果仍然节点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方法返回一个承诺。根据模式,承诺可以是resolve()'d或reject()'d 2.调用User.find。使用猫鼬,这将返回一个承诺,所以你可以这样做: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 
}) 
+2

这就是OP使用的[非常相同的反模式](http://stackoverflow.com/q/23803743/1048572)。 – Bergi