【问题标题】:How to avoid counting loop iterations in JavaScript Promises如何避免在 JavaScript Promises 中计算循环迭代
【发布时间】:2017-06-16 23:02:32
【问题描述】:

我最近开始使用 Promise,例如,我可以等到我用 x 条记录更新数据库,然后再执行下一个函数。我发现自己计算循环迭代是为了在正确的时间兑现承诺。例如:

var updateAccounts = function(accounts) {
  var promise = new Promise(function(resolve, reject) {
      var counter = 0;
      accounts.forEach(function(account) {

        db.collection('accounts').update({
          name: account.name
        }, {
          $set: {
            balance: account.balance
          }
        });
        counter++
        if (counter == accounts.length) {
          resolve('accounts updated');
        }
      });
    }
  });
  return promise;
}

有没有办法等到循环完成而不计算迭代?只是感觉有点老套,但我不确定这是否真的是个问题。

【问题讨论】:

  • 您无需等待更新完成。循环是同步的,更新不是。它们在循环早已结束时并行发生。查看Promise.all()
  • 这是 mongodb 吗?猫鼬?
  • @Thomas 所以你的意思是 promise.all,每次更新都是一个承诺?
  • @trincot 这是 mongodb

标签: javascript loops promise es6-promise


【解决方案1】:

根据MDN

Promise 对象表示异步操作的最终完成(或失败)及其结果值。

基本上这意味着Promise 应该跟踪单个异步操作的结果。

但是,在您的示例中,您在一个Promise 中执行了多个异步操作(即db.collection('accounts').update(...))。您不得不依靠交互计数来跟踪完整性,而不是依赖承诺来做到这一点。

要解决此问题(双关语:D),您的每个异步请求都应该有自己的Promise

由于您有多个更新和多个承诺,您可以使用Promise.all 来捕获所有承诺何时成功完成。

这是您的代码示例的快速改编:

var updateAccounts = function(accounts) {
    var promises = [];
    accounts.forEach(function(account) {
        var promise = new Promise(function(resolve, reject) {
            db.collection('accounts').update({
              name: account.name
            }, {
              $set: {
                balance: account.balance
              }
            });
        });
        promises.push(promise);
    });

    Promise.all(promises).then(function(arrPromises) { 
        console.log("All promises resolved.");
    }).catch(function(failedPromise) {
        console.log("Something failed.");
    });

}

我的示例中唯一缺少的是在db.collection('accounts').update(...) 成功执行后调用resolve。更新成功完成后,您必须调用resolve,或者如果更新失败,您必须调用reject。这就是它已经完成的承诺。

如果没有它,我的代码示例将无法工作,但从您的原始代码示例中并不清楚应该为db.collection('accounts').update(...) 指定回调的位置——所以我省略了它。

【讨论】:

    【解决方案2】:

    你可以在 foreach 之后尝试吗?

    var updateAccounts = function(accounts) {
      var promise = new Promise(function(resolve, reject) {
          ...
          accounts.forEach(function(account) {
            ...
          });
        <---Here<--
        }
      });
      return promise;
    }
    在循环内检查 foreach 的完成似乎很奇怪。也许您想确保帐户数组有一些元素?您也可以在循环外检查它的零或非零长度。

    【讨论】:

    • 我想我不明白 async bs sync 但基本上我想确保循环已经完成,然后再转到下一个函数。最好的方法是什么? foreach 默认会这样做吗?
    • 我最终取消选择其他答案并选择了这个。你是对的,我可以在循环后解决。出于某种原因,我有一次经历让我觉得我必须计算循环,这是不正确的。谢谢,您为我节省了大量时间!
    • 这个答案是完全错误的。我强烈建议您重新阅读下面的答案。
    • 谢谢兰德尔。应该是评论吧。当然你是对的,只是检查所有迭代都完成不会告诉你一堆异步操作已经完成
    • 关于这一点,似乎没有任何异步完成回调。我想知道承诺是否按预期使用?
    猜你喜欢
    • 2017-06-04
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-26
    • 1970-01-01
    • 2015-08-04
    • 2018-12-06
    相关资源
    最近更新 更多