Подтвердить что ты не робот

Node.js - ждать нескольких асинхронных вызовов

Я пытаюсь сделать несколько запросов MongoDB до того, как я создам шаблон Jade, но я не могу понять, как подождать, пока все запросы 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
    });

};
4b9b3361

Ответ 1

Я большой поклонник подчеркивания /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(), ваш код читается естественно: сверху вниз.

Ответ 2

Предполагая, что вы хотите выполнить две операции параллельно, а не ждать завершения до начала следующего, вам нужно будет отслеживать, сколько операций было выполнено в каждом обратном вызове.

В 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, так как пример инструмента, облегчающего управление такими вещами.

Ответ 3

Вы можете использовать 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
});

Ответ 4

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 parallel map:

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

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

Ответ 5

Это похоже на наименьшие строки кода, использующие async/wait:

async function getData() {
  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() служит в качестве Promise.all() чтобы не злоупотреблять функцией ожидания.