2013-08-02 153 views
32

我试图在呈现Jade模板之前进行多个MongoDB查询,但我无法完全弄清楚如何等待所有Mongo查询在呈现模板之前完成。Node.js - 等待多个异步调用

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

    }; 

回答

17

假设你要运行并行两种操作,而不是等待一个完成启动下一个之前,你需要跟踪有多少行动在每个回调完成。

在原料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库作为一个工具的例子,以便于管理这类事情。

+0

很干净。尼斯。 –

+0

这将有一个竞争条件。如果两个异步操作直到它们调用complete()之前执行完毕,那么它们都可以用必要的条件调用它,以执行complete()中的if语句的主体。不太可能,但可能。 – 2017-06-06 16:30:03

+0

@ ghert85在多线程环境中,你会是对的,但node.js是单线程的。所以直到它返回到事件循环之后,代码才能被中断,并且这种竞争条件不会发生。 –

5

您可以使用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 
}); 
52

我下划线/ 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()语法定义函数的定义,你的代码读取自然:顶部至底部。使用Wait.for

+0

非常好,谢谢:) – iConnor

1

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

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,所以你可能不得不调整通话。