webentwicklung-frage-antwort-db.com.de

Node.js - Warten Sie auf mehrere asynchrone Aufrufe

Ich versuche, mehrere MongoDB-Abfragen zu erstellen, bevor ich eine Jade-Vorlage rendere, aber ich kann nicht ganz herausfinden, wie ich warten muss, bis alle Mongo-Abfragen abgeschlossen sind, bevor die Vorlage gerendert wird. 

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

};
33

Ich bin ein großer Fan von Underscore/lodash, daher verwende ich normalerweise _.after, wodurch eine Funktion erstellt wird, die erst ausgeführt wird, nachdem sie eine bestimmte Anzahl von Malen aufgerufen wurde.

var finished = _.after(2, doRender);

asyncMethod1(data, function(err){
  //...
  finished();
});

asyncMethod2(data, function(err){
  //...
  finished();
})

function doRender(){
  res.render(); // etc
} 

Da JavaScript die Definition der mit der function funcName()-Syntax definierten Funktionen aufhebt, liest sich Ihr Code natürlich: von oben nach unten.

55
ssafejava

Angenommen, Sie möchten die beiden Vorgänge parallel ausführen und müssen nicht warten, bis eine Operation abgeschlossen ist, bevor Sie mit der nächsten beginnen. Sie müssen nachverfolgen, wie viele Vorgänge in jedem Rückruf abgeschlossen wurden.

In raw node.js Javascript könnte dies folgendermaßen geschehen:

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

};

Grundsätzlich passiert hier, dass Sie am Ende jedes Vorgangs prüfen, ob alle abgeschlossen sind, und an diesem Punkt den Vorgang beenden.

Wenn Sie viele dieser Dinge ausführen, werfen Sie einen Blick auf die Bibliothek async als Beispiel eines Tools, um die Verwaltung dieser Art zu vereinfachen.

18
Chris Tavares

Sie können async module verwenden:

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
});
6
S.D.

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

};

Paralleles Anfordern mit 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);
}

Ich bin nicht mit Mongo vertraut, daher müssen Sie möglicherweise die Anrufe anpassen.

1
Lucio M. Tato

Dies scheint die geringste Anzahl von Codezeilen zu sein, die wait verwenden:

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

Randnotiz: In diesem Fall dient wait als Promise.all() Achten Sie darauf, die wait-Funktion nicht zu missbrauchen.

0
GavinBelson