【问题标题】:How to break loop inside a promise?如何打破承诺中的循环?
【发布时间】:2014-03-12 12:41:16
【问题描述】:

我正在使用 Bluebird 库进行某种 QA(问题/答案)应用程序。所以这是场景:

  1. 用户在表单中填写一些问题(例如 5 个问题)的答案。
  2. 一个问题有多个可能的答案:“问题有很多答案”
  3. 使用node.bcrypt 在数据库上对答案进行加密 (bcrypt)
  4. 循环遍历答案时,如果用户答案匹配,则无需继续检查该问题的答案。

所以在做同步的事情时,这是一个常见的问题,但我有点迷失了用 promises 做异步。

这是我不知道如何进行的示例:

  .then(function(answers) {
    var compare = Promise.promisify(bcrypt.compare);
    // foreach answer, I need to check like this
    // compare(answer.password, user.password).then(function(match){
    //      if (match) break; <-- something like this
    //   })
  })

【问题讨论】:

  • 您可能必须在循环之前单独获取加密答案,并在回调内部启动循环并进行基本检查(if hash == password) break;
  • @tymeJV 我想我不能这样做,因为当我使用 bcrypt 对密码进行哈希处理时,会从数据库先前生成的值中生成不同的值......这就是我需要 bcrypt 的原因比较函数...也许我错了...
  • 不要把我的 bcrypt 回购放在我面前,但这听起来不错 - 回调地狱:\ - 这篇文章可能会有所帮助:stackoverflow.com/questions/13214862/…

标签: javascript node.js asynchronous promise bluebird


【解决方案1】:

假设你想按顺序调用compares,这样就可以了:

.then(function(answers) {
    var compare = Promise.promisify(bcrypt.compare),
        i = 0;
    return Q(false).then(function checkNext(res) {
        return res ||
               i<answers.length && compare(answers[i++].password, user.password)
                                     .then(checkNext);
    });
})

它将“递归”遍历answers 数组,在第一个true 结果处停止。要返回正确答案(而不仅仅是 true 表示“找到”)或 null(如果未找到),如 @Noseratio 的代码,您可以使用

    var i = 0, answer;
    return Q(false).then(function checkNext(res) {
        return res ? answer : (i<answers.length || null) && compare((answer = answers[i++]).password, user.password).then(checkNext);
    });

或者越详细越好

function next(i) {
    if (i < answers.length)
        return compare(answers[i].password, user.password).then(function(res) {
             return res ? answers[i] : next(i+1);
        });
    else
        return null;
}
return next(0);

【讨论】:

    【解决方案2】:

    以下解决方案(未经测试)实现了一个状态机来模拟foreach 循环。 result 承诺在找到匹配项或没有更多答案可比较时解决:

      .then(function(answers) {
        var result = new Promise();
        var i = 0;
        function nextStep() {
          if (i >= answer.length)
            result.resolve(null);
          else {
            var answer = answers[i];
            if (compare(answer.password, user.password).then(function(match) {
              if (match)
                result.resolve(answer);
              else {
                i++;
                nextStep(); // do the next step
              }
            })
          }
        }
        process.nextTick(nextStep); // do the first step asynchronously    
        return result; // return the result as a promise
      });
    

    【讨论】:

      【解决方案3】:

      这可能是一个简单的解决方案:

      let breakLoop = false
      for (let answer of arr) {
        if (breakLoop) continue
        compare(answer.password, user.password)
          .then(match => {
            if (match) breakLoop = true
          })
          .catch(err => breakLoop = true)
      }
      

      【讨论】:

        猜你喜欢
        • 2017-07-26
        • 1970-01-01
        • 2018-09-29
        • 2017-11-23
        • 1970-01-01
        • 1970-01-01
        • 2018-10-13
        • 2020-02-23
        相关资源
        最近更新 更多