我遇到节点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>
答案 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函数将其整理得更多