【问题标题】:How do I wait until an asynchronous process inside a loop is finished before exiting the loop?如何在退出循环之前等待循环内的异步进程完成?
【发布时间】:2017-01-31 14:50:26
【问题描述】:

我在 JavaScript forEach 循环中运行了一些异步代码。我想等到异步进程中的代码运行完毕再在循环之后继续。

示例如下:

ids 是一个字符串数组。 db 是我创建的用于 MongoDB 的节点模块

var appIdsNotFound = "";
var count = 0;
ids.forEach(function(id) {
    output[count] = {};
    //console.log(id);
    db.findApp(id, function(error, result) {
        if(error) {
            fatalError = true;
            console.log(error);
        } else {
            if (result) {
                output[count] = result;
                //console.log(output[count]);
                count++;
            } else {
                appNotFound = true;
                appIdsNotFound += id + ", ";
                console.log(appIdsNotFound);
            }
        }
    });
});

//more code that we want to wait before executing

有没有办法在执行循环外的其余代码之前等待,如果是,我将如何去做。

【问题讨论】:

  • 你考虑使用Promise吗?用 promise 包装你的异步函数,在错误调用拒绝和成功解决时,然后将所有 promise 对象收集到数组并执行 Promise.all()
  • 我从未使用过承诺。我看到的每个教程都不一样。猜猜是时候学习了。

标签: javascript node.js mongodb loops asynchronous


【解决方案1】:
  1. 假设db 是访问您的数据库的某个模块,请尝试查找同步版本。这假设您可以使用同步,因为您正在尝试以这种方式编写它,在继续之前等待一切。

  2. 如果您的 db 库使用 Promise,您可以将它与 Promise.all 结合使用。为每个项目触发一个请求,将它们的所有 Promise 收集到一个数组中,并将它们提供给 Promise.all。来自Promise.all 的承诺将在所有承诺解决后解决。

    const promises = ids.map(id => db.promiseReturningFindApp(id));
    const allRequests = Promise.all(promises).then(responses => {
      // responses is an array of all results
    });
    
  3. 如果您的 API 没有返回承诺的版本,请将 db.findApp 包装在承诺中,执行建议 #2。

    function promiseReturningFindApp(id){
      return new Promise((resolve, reject) => {
        db.findApp(id, (error, result) => {
          if(error) reject(error);
          else resolve(result);
        });
      });
    }
    

选项 2 和 3 是异步的,因此,从技术上讲,您不必“等待”。因此,后面需要执行的代码只能驻留在回调中。

【讨论】:

  • db 是来自 npm 的 mongoose.js 的实现。它包含我的模式和用于读取和写入数据库的各种函数。我已经异步编写了所有内容,以实现尽可能快的时间。
  • @JoelTrauger 是的,mongodb 已经支持 Promise,所以只需使用方法 #2
  • 我不认为 MongooseJS 完全支持 Promise,因为它需要我 require('mpromise'); 才能使 Promise 正常工作。我不熟悉那个 npm 包。
【解决方案2】:

你可以把每一项都变成一个函数,然后使用async

var async = require('async');

var output = [], appsNotFound = [];
var appRequests = ids.map((id) => (cb) => {
    db.findApp(id, (error, result) => {
        if (error) {
            appsNotFound.push(id);
            return cb();
        }
        output.push(id);
        return cb();    
    })
})

async.parallel(appRequests, () => {
    console.log('N# of Apps found',output.length);
    console.log("Ids not found:",appIdsNotFound.join(','))
    console.log("N# Apps not found:",appIdsNotFound.length)
})

如果数据库不处理,请尝试使用async.serial

如果你愿意,你可以用 Promise 做类似的事情,但这需要更少的代码。

【讨论】:

    猜你喜欢
    • 2020-08-02
    • 2020-01-04
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多