34

我试图在渲染 Jade 模板之前进行多个 MongoDB 查询,但我不太清楚如何等到所有 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
    });

};
4

5 回答 5

58

我是 underscore/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()您的代码自然读取:从上到下。

于 2013-08-02T07:57:04.440 回答
19

假设您希望并行运行这两个操作,而不是等待一个操作完成后再开始下一个操作,您需要跟踪每个回调中完成了多少操作。

在原始 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
            });
        }
    }

};

基本上这里发生的事情是,您在每个操作结束时检查它们是否都已完成,然后您完成操作。

如果您正在做很多此类事情,请查看异步库作为工具示例,以便更轻松地管理此类事情。

于 2013-08-02T04:05:52.097 回答
6

您可以使用异步模块:

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
});
于 2013-08-02T04:13:50.740 回答
1

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

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

};

Requesting in parallel using 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);
}

I'm not familiar with mongo, so you may have to adjust the calls.

于 2013-09-06T14:54:22.967 回答
1

这似乎是使用 await 的最少代码行:

var async = require("async"); //include async module
...
async function getData() { //make sure to use async function
  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()小心不要滥用等待功能。

于 2018-12-04T21:19:43.963 回答