web-dev-qa-db-fra.com

Node.js - attend plusieurs appels asynchrones

J'essaie de créer plusieurs requêtes MongoDB avant de générer un modèle Jade, mais je ne vois pas trop comment attendre que toutes les requêtes Mongo soient terminées avant de générer le modèle. 

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
Warrick FitzGerald

Je suis un grand fan de underscore/lodash, j'utilise donc généralement _.after, qui crée une fonction qui ne s'exécute qu'après avoir été appelé un certain nombre de fois.

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

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

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

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

Étant donné que javascript élève la définition des fonctions définies avec la syntaxe function funcName(), votre code se lit naturellement: de haut en bas.

55
ssafejava

En supposant que vous souhaitiez exécuter les deux opérations en parallèle plutôt que d'attendre la fin d'une opération avant de commencer la suivante, vous devrez suivre le nombre d'opérations terminées à chaque rappel.

En javascript raw.no.net.js, une façon de procéder est la suivante:

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

};

Fondamentalement, ce qui se passe ici, c’est que vous vérifiez à la fin de chaque opération si toutes les opérations sont terminées, puis vous terminez l’opération.

Si vous faites beaucoup de choses, jetez un coup d'œil à la bibliothèque async comme exemple d'outil facilitant la gestion de ce genre de choses.

18
Chris Tavares

Vous pouvez utiliser async module:

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

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

};

Demander en parallèle en utilisant 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);
}

Je ne connais pas mongo, vous devrez peut-être ajuster les appels.

1
Lucio M. Tato

Cela semble être la moindre ligne de code utilisant wait:

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

Note latérale: Dans ce cas, wait fait office de Promise.all(), veillez à ne pas abuser de la fonction wait.

0
HoosierCoder