简体   繁体   English

如何在承诺中打破循环?

[英]How to break loop inside a promise?

I'm doing kind of QA (Question/Answers) application using the Bluebird library. 我正在使用Bluebird库做一些QA(问题/答案)应用程序。 So here's the scenario: 所以这是场景:

  1. User fill the form with answers for some number of questions (eg 5 questions). 用户填写表格并提供一些问题的答案(例如5个问题)。
  2. A question has more than 1 possible answer: "Question has many answers" 一个问题有多个可能的答案:“问题有很多答案”
  3. Answers are encrypted (bcrypt) on database using node.bcrypt 使用node.bcrypt在数据库上对Answers进行加密(bcrypt)
  4. When looping through answers, if user answer matches, there's no need to continue checking the answer for that question. 循环回答时,如果用户回答匹配,则无需继续检查该问题的答案。

So it's a common problem to solve when doing things synchronous, but I'm a little lost to do that async with promises. 所以当做同步事情时,这是一个常见的问题需要解决,但我有点迷失与promises异步。

Here's a sample of what I don't know how to proceed: 以下是我不知道如何处理的示例:

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

Assuming you want to call the compare s sequentially, this will do it: 假设您compare顺序调用compare ,这将执行此操作:

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

It will "recursively" step trough the answers array, stopping on the first true result. 它将“递归地”逐步通过answers数组,停止第一个true结果。 To return the correct answer (instead of just true for "found") or null (if not found) like @Noseratio's code, you could use 要返回正确的答案(而不仅仅是“找到”为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);
    });

or better the more verbose 或者更好,更详细

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

The following solution (untested) implements a state machine to simulate foreach loop. 以下解决方案(未经测试)实现状态机以模拟foreach循环。 The result promise is resolved when the match has been found, or when there is no more answers to compare: 找到匹配项后,或者没有更多答案要比较时, 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
  });

It could be a simple solution: 这可能是一个简单的解决方案:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM