【问题标题】:How to get the value of the first promise that succeeds in a chain of promises如何获取在一系列 Promise 中成功的第一个 Promise 的值
【发布时间】:2014-09-22 12:49:04
【问题描述】:

我正在寻找一种方法来返回一个承诺只有在另一个承诺失败时

我该怎么做?

我的承诺看起来像这样(当然我已经删除了不相关的代码):

getUserByUsername = function(username) {
    return promise(function(resolve, reject) {
       user = userModel.getByUsername(username);
       if ( user ) { resolve(user); } else { reject("user not found"); }
    });
};

getUserByEmail = function(email) {
    return promise(function(resolve, reject) {
       user = userModel.getByEmail(email);
       if ( user ) { resolve(user); } else { reject("user not found"); }
    });
};

checkPassword = function(user, password) {
    return promise(function(resolve, reject) {
       if ( user.isValidPassword(password) ) { resolve() } else { reject("password mismatch"); }
    });
};

我想按以下顺序组合它们

  1. 致电getUserByUsername,如果拒绝则致电getUserByEmail
  2. 返回从上述两个承诺中解决的人的值,或者如果两个承诺都失败则拒绝整个链。
  3. 使用该值调用checkPassword,如果它拒绝,则拒绝整个链

到目前为止,我已经完成了这项工作,并且似乎有效。 (我正在使用when.js btw)

getUserByUsername(usernameOrEmail)
.then( 
    function(user) { return user; }, 
    function() { return getUserByEmail(usernameOrEmail) } 
)
.then( function(user) { return checkPassword(user, password) } )
.done( 
    function() { console.log('success'); }, 
    function(err) { console.log('failure', err) }
);

所以这段代码工作,但我很确定应该有更优雅的方式来做到这一点(我认为我的代码看起来更像是一个黑客)。

【问题讨论】:

    标签: javascript promise es6-promise


    【解决方案1】:

    类似的东西呢:

     getUserByUsername(usernameOrEmail).
     catch(getUserByEmail.bind(null, usernameOrEmail)).
     then(function(user){
         if(!isValidPassword(user, password)) throw new Error("Invalid Password");
     }).then(function(){
         // success
     }, function(){
        //fail
     });
    

    关键点:

    • 您可以throw 拒绝承诺,return 继续链。 Promise 构造函数几乎没有用处。
    • 您可以通过执行.then(null, function(){... 来省略.then 中的第一个参数,但是使用.catch 更简单,这是它的别名。更一般地说,.then 会忽略不是函数的参数。
    • 拒绝和返回值传播,如果您不通过.catch(或.then 的第二个参数)处理拒绝,它将简单地穿过链,直到您这样做。返回值也是如此 - 这就是为什么这里的前两行包含:
      • 尝试通过用户名获取用户
      • 如果失败,请通过电子邮件尝试。

    一般而言,您所描述的内容与同步代码中的承诺和异常并行非常常见。学习如何有效地做这类事情很重要。

    【讨论】:

    • 伙计,你太快了。当你在附近时,我没有机会写答案:-)
    • 非常感谢您的澄清。我想我明白了这个例子的意思,尽管我认为你在第二行错过了一个)。你不是说.catch(getUserByEmail.bind(null,usernameOrEmail)).then...吗?
    • 是的,是的,我做到了。很好的收获。
    猜你喜欢
    • 2019-09-17
    • 2016-12-26
    • 1970-01-01
    • 2016-12-20
    • 2017-10-26
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    • 2017-10-11
    相关资源
    最近更新 更多