Express.js异步问题

时间:2014-02-12 14:46:47

标签: javascript node.js express

我遇到节点js的异步性问题,我有一个这个函数

var sendData = function(req, res) {
    var requestId = req.params.id;
    var dataForSend = [];
    database.collection('songs').find({player_id:new ObjectID(requestId)}).toArray(function(err, player) {

        _.each(songs , function(song){
            var songID = song._id;
            song[song] = song;

            functions.generateViewData(song,data,false, function(playerData, song) {
                var dataForSong = {
                    // some code here
                }
                dataForSend.push(dataForChart);
                console.log("Kako ovo ne radi leb ti jebem" + JSON.stringify(dataForChart));
            });
        });
        res.send(dataForSend);
    });

}

我的问题是应用程序不要等待每个循环完成并填充dataForSend数组,并且每次我res.send(dataForSend)空数组,如何等待此循环完成然后将dataForSend数组发送到客户端? / p>

3 个答案:

答案 0 :(得分:1)

将计数器初始化为您拥有的歌曲数量。然而,你在每首歌曲的循环中减少它。当您达到0时,您将发送数据。

var songsRemaining = songs.length;
_.each(songs , function(song){
     var songID = song._id;
     song[song] = song;

     functions.generateViewData(song,data,false, function(playerData, song) {
         var dataForSong = {
             // some code here
         }
         dataForSend.push(dataForChart);

         songsRemaining--;

         if (songsRemaining === 0) {
              res.send(dataForSend);         
         }
     });
});

您也可以反转逻辑,将计数器初始化为0,递增计数器并检查何时达到歌曲数量。这只是一个习惯问题,我通常更喜欢这种情况的倒数逻辑。

答案 1 :(得分:0)

我建议使用promises。然后,您可以在迭代时创建一个异步承诺数组,然后在返回“发送”数据之前等待所有承诺完成。

Q(https://github.com/kriskowal/q)是一个伟大的承诺库。

这样的事可能......

var Q = require("Q");

var sendData = function(req, res) {
    var requestId = req.params.id;
    var dataForSend = [];
    database.collection('songs').find({player_id:new ObjectID(requestId)}).toArray(function(err, player) {
    var promises = [];

        _.each(songs , function(song){
            var songID = song._id;
            song[song] = song;

        var promise = Q.fcall(function() {

                functions.generateViewData(song,data,false, function(playerData, song) {
                    var dataForSong = {
                        // some code here
                    }
                    dataForSend.push(dataForChart);
                    console.log("Kako ovo ne radi leb ti jebem" + JSON.stringify(dataForChart));
                });
        });
        promises.push(promise);
        });

    Q.all(promises).then(function() {
            res.send(dataForSend);
    });
    });

}

答案 2 :(得分:0)

它实际上等待_.each循环完成,只是你的_.each循环在你的所有functions.generateViewData调用完成之前完成。因为functions.generateViewData是异步的,所以_.each迭代在functions.generateViewData调用回调函数之前返回。

我建议你使用asyncjs,它有一个async.each功能,非常适合你的用例。你可以这样做:

var sendData = function(req, res) {
    var requestId = req.params.id;
    var dataForSend = [];
    database.collection('songs').find({player_id:new ObjectID(requestId)}).toArray(function(err, player) {

        async.each(songs, 
           function(song,callback){
               functions.generateViewData(song,data,false, function(playerData, song) {
                    var dataForSong = {
                        // some code here
                    }
                    dataForSend.push(dataForChart);
                    console.log("Kako ovo ne radi leb ti jebem" + JSON.stringify(dataForChart));
                    //you call the callback with no parameters or null if no error occurs
                    callback(); 
               });
           }, 
           function(err){
               //since you never called callback with an error err will always be null and this function will be called when all your songs finished processing
               res.send(dataForSend);
           }
        );
    });
}

您还可以使用其他asyncjs函数将其整理得更多