我正在尝试遍历我从函数获得的响应,并且数据存在于函数中但在渲染代码执行之前没有足够快地保存到数组中,从而呈现空数组。有可能以某种方式等待循环结束还是有更有效的方法?使用控制台日志清楚地表明数组在我的res.send命令之后被填充。
router.get('/summoner/:playerName', function(req, res, next) {
var summonerName = req.params.playerName;
lolapi.Summoner.getByName(summonerName, function (error, summoner) {
if (error) console.log('Summoner not Found!');
console.log(summoner);
var summonerId = summoner[summonerName].id;
var options = {beginIndex: 0, endIndex: 2};
var matchIds = [];
var gameData = [];
lolapi.MatchList.getBySummonerId(summonerId, options, function (error, matchlist) {
if (error) console.log('Summoner needs to play some games!');
for (var i = 0; i < matchlist['matches'].length; i++) {
matchIds[i] = matchlist['matches'][i].matchId;
}
for (var i = 0; i < matchIds.length; i++) {
lolapi.Match.get(matchIds[i], function(error, game) {
// game variables is object format
gameData[i] = game;
});
};
// outputting array to browser but is empty
res.send(gameData);
});
});
});
答案 0 :(得分:3)
是的,这是一个异步问题。通常的dupetarget是How do I return the response from an asynchronous call?,并且值得在那里阅读答案,但是你有几件事情在这里我认为应该直接解决:
您的lolapi.Match.get
完成是异步调用的,所以:
你不能期待这些电话&#39;在for
循环结束之前调用的回调(实际上,您已经保证他们不会被调用),并且
i
在保存到gameData
时不会获得您期望的值,因为它已经一直增加到matchIds.length
之前发生第一次回调。
所以你希望回调关闭其他而不是i
,并且还有办法跟踪你已经获得了多少回调(因为它们可以发生故障,因此我们无法使用gameData.length
):
router.get('/summoner/:playerName', function(req, res, next) {
var summonerName = req.params.playerName;
lolapi.Summoner.getByName(summonerName, function(error, summoner) {
if (error) console.log('Summoner not Found!');
console.log(summoner);
var summonerId = summoner[summonerName].id;
var options = {
beginIndex: 0,
endIndex: 2
};
var matchIds = [];
var gameData = [];
var received = 0; // ***
lolapi.MatchList.getBySummonerId(summonerId, options, function(error, matchlist) {
if (error) console.log('Summoner needs to play some games!');
for (var i = 0; i < matchlist['matches'].length; i++) {
matchIds[i] = matchlist['matches'][i].matchId;
}
for (var i = 0; i < matchIds.length; i++) {
getOne(i); // ***
}
function getOne(index) { // ***
lolapi.Match.get(matchIds[index], function(error, game) { // ***
// game variables is object format // ***
gameData[index] = game; // ***
if (++received === matchIds) { // ***
// got all responses, we can output now // ***
res.send(gameData); // ***
} // ***
}); // ***
} // ***
});
});
});
旁注:重新上一行:
if (error) console.log('Summoner not Found!');
当然你想return
那里(并且可能通过res.send
发送一些内容),而不是继续使用函数的逻辑?
附注2:您可以使用Array#forEach
来简化:
router.get('/summoner/:playerName', function(req, res, next) {
var summonerName = req.params.playerName;
lolapi.Summoner.getByName(summonerName, function(error, summoner) {
// *** Probably need to do more here on eror
if (error) console.log('Summoner not Found!');
console.log(summoner);
var summonerId = summoner[summonerName].id;
var options = {
beginIndex: 0,
endIndex: 2
};
lolapi.MatchList.getBySummonerId(summonerId, options, function(error, matchlist) {
// *** Probably need to do more here, or at least not continue
if (error) console.log('Summoner needs to play some games!');
var gameData = [];
var received = 0;
matchlist.matches.forEach(function(entry, index) { // ***
lolapi.Match.get(entry.matchId, function(error, game) {
// game variables is object format
gameData[index] = game;
if (++received === matchlist.matches.length) {
// got all responses, we can output now
res.send(gameData);
}
});
});
});
});
});