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

时间:2013-08-02 03:49:29

标签: javascript node.js mongodb

我正在尝试在渲染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
    });

};

5 个答案:

答案 0 :(得分:56)

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

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

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

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

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

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

答案 1 :(得分:18)

假设你想要并行运行这两个操作而不是等到一个操作完成,那么你需要跟踪每个回调中完成的操作数量。

在raw 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
            });
        }
    }

};

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

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

答案 2 :(得分:6)

您可以使用async模块:

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

答案 3 :(得分:1)

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

使用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
        }
    );

};

使用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);
}

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

答案 4 :(得分:0)

这似乎是使用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();

旁注:在这种情况下,等待是作为Promise.all()的作用,请注意不要滥用等待功能。