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
});
};
Ответы
Ответ 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()
чтобы не злоупотреблять функцией ожидания.