Node.js - 等待多个异步调用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18008479/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:11:00  来源:igfitidea点击:

Node.js - wait for multiple async calls

javascriptnode.jsmongodb

提问by Warrick FitzGerald

I'm trying to make multiple MongoDB queries before I render a Jade template, but I can't quite figure out how to wait until all the Mongo Queries are completed before rendering the template.

我正在尝试在渲染 Jade 模板之前进行多个 MongoDB 查询,但我无法弄清楚如何在渲染模板之前等待所有 Mongo 查询完成。

exports.init = function(req, res){


    var NYLakes = {};
    var NJLakes = {};
    var filterNY = {"State" : "NY"};
    db.collection('lakes').find(filterNY).toArray(function(err, result) {
        if (err) throw err;
        NYLakes = result;
    });

    var filterNJ = {"State" : "NJ"};
    db.collection('lakes').find(filterNJ).toArray(function(err, result) {
        if (err) throw err;
        NJLakes = result;
    });

    res.render('explore/index', {
            NYlakes: NYLakes,
            NJlakes: NJLakes
    });

};

回答by ssafejava

I'm a big fan of underscore/lodash, so I usually use _.after, which creates a function that only executes after being called a certain number of times.

我是下划线/lodash 的忠实粉丝,所以我通常使用_.after,它创建了一个函数,该函数仅在被调用一定次数后才执行。

var finished = _.after(2, doRender);

asyncMethod1(data, function(err){
  //...
  finished();
});

asyncMethod2(data, function(err){
  //...
  finished();
})

function doRender(){
  res.render(); // etc
} 

Since javascript hoists the definition of functions defined with the function funcName()syntax, your code reads naturally: top-to-bottom.

由于 javascript 提升了使用function funcName()语法定义的函数的定义,因此您的代码读起来很自然:从上到下。

回答by Chris Tavares

Assuming you want to run the two operations in parallel rather than waiting for one to finish before starting the next, you'll need to track how many operations have completed in each callback.

假设您想并行运行这两个操作,而不是等待一个完成后再开始下一个,您需要跟踪每个回调中已完成的操作数。

In raw node.js javascript, one way to do this would be this:

在原始 node.js javascript 中,一种方法是:

exports.init = function(req, res){
    var NYLakes = null;
    var NJLakes = null;
    var filterNY = {"State" : "NY"};

    db.collection('lakes').find(filterNY).toArray(function(err, result) {
        if (err) throw err;
        NYLakes = result;
        complete();
    });

    var filterNJ = {"State" : "NJ"};
    db.collection('lakes').find(filterNJ).toArray(function(err, result) {
        if (err) throw err;
        NJLakes = result;
        complete();
    });

    function complete() {
        if (NYLakes !== null && NJLakes !== null) {
            res.render('explore/index', {
                NYlakes: NYLakes,
                NJlakes: NJLakes
            });
        }
    }

};

Basically what's happening here is that you check at the end of each operation if all of them have finished, and at that point you finish off the operation.

基本上这里发生的事情是您在每个操作结束时检查是否所有操作都已完成,然后您完成操作。

If you're doing a lot of these things, take a look at the asynclibrary as an example of a tool to make it easier to manage this sort of thing.

如果您正在做很多这样的事情,请查看async库作为一个工具示例,以便更轻松地管理此类事情。

回答by S.D.

You can use asyncmodule:

您可以使用异步模块:

var states = [{"State" : "NY"},{"State" : "NJ"}];

var findLakes = function(state,callback){
  db.collection('lakes').find(state).toArray(callback);
}

async.map(states, findLakes , function(err, results){
    // do something with array of results
});

回答by Lucio M. Tato

Wait.for https://github.com/luciotato/waitfor

等待https://github.com/luciotato/waitfor

using Wait.for:

使用等待:

exports.init = function(req, res){

    var NYLakes = {};
    var NJLakes = {};

    var coll = db.collection('lakes');

    var filterNY = {"State" : "NY"};
    var a = wait.forMethod(coll,'find',filterNY);
    NYLakes = wait.forMethod(a,'toArray');

    var filterNJ = {"State" : "NJ"};
    var b = wait.forMethod(coll,'find',filterNJ);
    NJLakes = wait.forMethod(b,'toArray');

    res.render('explore/index',
        {
            NYlakes: NYLakes,
            NJlakes: NJLakes
        }
    );

};

Requesting in parallel using wait.for parallel map:

使用 wait.for 并行映射并行请求:

exports.init = function(req, res){

    var coll = db.collection('lakes');

    //execute in parallel, wait for results
    var result = wait.parallel.map(
                    [{coll:coll,filter:{"State" : "NY"}}
                    , {coll:coll,filter:{"State" : "NJ"}}]
                    , getData);

    res.render('explore/index',
        {
            NYlakes: result[0],
            NJlakes: result[1]
        }
    );

};

//map function
function getData(item,callback){
try{
    var a = wait.forMethod(item.coll,'find',item.filter);
    var b = wait.forMethod(a,'toArray');
    callback (null, b);
} catch(err){
    callback(err);
}

I'm not familiar with mongo, so you may have to adjust the calls.

我对 mongo 不熟悉,所以你可能需要调整调用。

回答by GavinBelson

This seems like the least lines of code using await:

这似乎是使用 await 的最少代码行:

var async = require("async"); //include async module
...
async function getData() { //make sure to use async function
  var NYlakes = await db.collection('lakes').find(filterNY); //can append additional logic after the find() 
  var NJlakes = await db.collection('lakes').find(filterNJ);

  res.json({"NYLakes": NYLakes, "NJLakes": NJLakes}); //render response
}

getData();

Side note: In this case await is serving as a Promise.all()be careful not to abuse the await function.

旁注:在这种情况下, await 用作Promise.all()注意不要滥用 await 功能。