【问题标题】:How can I wait for asynchronous callback inside Javascript synchronous loop to finish before proceeding如何在继续之前等待 Javascript 同步循环中的异步回调完成
【发布时间】:2017-06-30 00:40:38
【问题描述】:

我知道我在同一个句子中使用了“等待”和“异步”这两个词,这是没有意义的。但我想知道是否有人可以建议我解决我的问题。

我有一个在 mongodb 返回的文档数组上运行的 for 循环。现在,根据某些逻辑,我需要删除某些文档。只有在我完成删除文档之后,我才能调用我的下一个方法。如下所示:

mymongodbconnection.find({}).toArray(function(err, documents) {
if (!err && documents.length !== 0) {
  documents.forEach(function(document) {

      if( someCheckPerformed(document)){
        console.log('keeping');
      }else{
        console.log('removing');
mymongodbconnection.remove({_id:document._id},fun(err,result){});
      }
  });

 notifyAdminAboutChange();
} else {
  logger.warn('No existing UA docs to filter');
}
});

现在,如您所见,我需要调用 notifyAdminAboutChange();仅在 for 循环完成对所有文档的迭代并删除需要删除的文档之后。

我的问题:

  1. 我可以阻止 for 循环执行以等待删除完成吗?
  2. 如果 1 不可能,我该如何实现这个用例?

【问题讨论】:

  • 答案可能是使用promise和promise-do-whilst...但是什么是mongodBCollectionInstance?此外,您可能需要将 writeConcern 与 Mongo 的删除功能一起使用
  • 你不能让 Javascript “等待”。相反,您必须更改循环的结构以对异步操作进行排序,或者您必须全部启动它们并跟踪它们何时全部完成,例如Promise.all()。一些相关答案:How to synchronize a sequence of promises?Asynchronous function inside a javascript for loop

标签: javascript node.js callback


【解决方案1】:

使用 promise - 为每个要删除的文档创建一个,然后等待它们全部解决(使用 Promise.all),然后再调用您的函数。

mongodBCollectionInstance.find({}).toArray(function(err, documents) {
  if (!err && documents.length !== 0) {
    var promises = [];

    documents.forEach(function(document) {
      if( someCheckPerformed(document)){
        console.log('keeping');
      }else{
        console.log('removing');
        promises.push(new Promise(function (fulfill, reject){
          mongodBCollectionInstance.remove(
            {_id:document._id},
            function (err, result) {
              fulfill();
            });
        }))
      }
    });
    Promise.all(promises).then(function () {
      notifyAdminAboutChange();
    });
  } else {
    logger.warn('No existing UA docs to filter');
  }
});

【讨论】:

  • 嘿@Greg,感谢您帮助我。快速提问:如果我在某些承诺上调用完成并在其他承诺上拒绝,Promises.all 是否仍会被调用,或者是否所有承诺的需要都被满足才能调用 Promises.all?
【解决方案2】:

我不知道任何 JS 轻率的手可以轻松地填充到您现有的结构中,但是如果您重新安排一点并且对递归解决方案保持开放的心态,您可能会达到您想要的结果:

coll.find({}).toArray((err, docs)=> {
    (function checkDoc(i){
        if(i >= docs.length) return;
        else if(pred(docs[i])) checkDoc(i + 1);
        else coll.remove({_id: docs[i]._id}, _=> checkDoc(i + 1));
    })(0);
})

这样,文档是按顺序检查的,只有在当前文档处理完毕后才会处理下一个文档。

demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    • 2017-11-14
    • 1970-01-01
    • 2018-11-28
    相关资源
    最近更新 更多