2013-08-02 2 views
32

Я пытаюсь сделать несколько запросов MongoDB до того, как я отрисую шаблон Jade, но я не могу понять, как подождать, пока все запросы 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(), они могут оба вызвать его с необходимым условием для выполнения тела оператора if в complete(). Вряд ли, но возможно. –

+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(), ваш код читает естественно: сверху-снизу.

+0

Отлично, спасибо :) – iConnor

1

Wait.for 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); 
} 

Я не знаком с монго, так что вам, возможно, придется настраивать вызовы.

Смежные вопросы