2013-08-02 35 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

あなたが並列に2つの操作を実行したいと仮定するのではなく、次の開始前に終了する1を待っている、あなたは、各コールバックで完了しているどのように多くの操作を追跡する必要があります。生のNode.jsのJavaScriptで

、これを実行するための1つの方法は、このようになります:

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ライブラリをご覧ください。私はアンダースコア/ lodashの大ファンだ

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

非常にきれいです。ニース。 –

+0

これは競合状態になります。両方の非同期操作がcomplete()を呼び出す直前まで実行されると、complete()内のifステートメントの本体を実行するのに必要な条件で呼び出すことができます。おそらく、しかし可能です。 –

+0

@ ghert85マルチスレッド環境では正しいでしょうが、node.jsはシングルスレッドです。したがって、イベントループに戻り、この競合状態が発生するまで、コードを中断することはできません。 –

5

あなたはasyncモジュールを使用することができます。

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並列マップ使用して並列に要求

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使用

52

ので、私は通常は特定の回数呼び出された後に実行される関数を作成し_.afterを使用します。

+0

優秀、ありがとう:) – iConnor

1

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

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を使用しているため、通話を調整する必要があります。

関連する問題