2013-08-02 206 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,所以你可能不得不調整通話。