3

我正在编写一个多人游戏(mongojs,nodejs)并试图弄清楚如何根据游戏结果更新用户统计数据。我已经编写了用于计算所有赛后统计数据的代码。当我尝试在 for 循环中更新用户的统计信息时,问题就来了。这是我得到的:

//Game Stats
var tempgame = {
    gameid: 1234,
    stats: [
        {
            score: 25,
            user: 'user1'
        },
        {
            score: 25,
            user: 'user2'
        }
    ]
}


for(i = 0; i < tempgame.stats.length; i++){
    db.users.find({ username: tempgame.stats[i].user }, function(err, res){
        if( err != null){
            //handle errors here.
        } else {
            var userstats = res[0].stats;
            if( tempgame.stats[i].score > userstats.bestscore ){ //this is where it chokes 
                userstats.bestscore = tempgame.stats[i].score;
            }

            //code here to pass back new manipulated stats
        }
    });
}

一切正常,直到我尝试在回调函数中使用 tempgame 对象。它说“无法读取未定义的属性'分数'”。这只是一个范围问题吗?

另外我认为这可能是回调函数本身的问题。也许循环会在回调运行之前增加。但即使在那种情况下,分数也应该在那里,它只是从错误的数组索引中提取出来的......这就是让我相信它可能只是一个范围问题的原因。

任何帮助将不胜感激。

4

3 回答 3

7

您被臭名昭著的“在循环中定义函数”问题所困扰。

改用“forEach”:

tempgame.stats.forEach(function (stat) {
    db.users.find({ username: stat.user }, function(err, res){
        if( err != null){
            //handle errors here.
        } else {
            var userstats = res[0].stats;
            if( stat.score > userstats.bestscore ){ //this is where it chokes 
                userstats.bestscore = stat.score;
            }

            //code here to pass back new manipulated stats
        }
    });
});
于 2013-01-22T19:13:16.580 回答
2

您的问题的一部分正如 mjhm 在他对您问题的回答中所说的那样,并且正如您所怀疑的那样。在i调用回调之前,变量正在更改。

问题的另一半是因为您的数据库调用尚未返回。由于 NodeJS 的异步特性,您的循环将在数据库调用完成之前完成。此外,您的数据库调用不一定按照您调用它们的顺序返回。您需要的是某种流控制,例如async.js。Usingasync.map将允许您并行地对数据库进行所有调用,并在所有数据库调用完成后将它们作为可以使用的值数组返回。

async.map(tempgame.stats, function(stat, callback){
  db.users.find({ username: stat.user }, function(err, res){
      if( err != null){
          callback(err);
      } else {
          callback(null, res[0].stats);
      }
  });      
}, function(err, stats){
  if(err){
    //handle errors
  } else{
    stats.forEach(function(stat){
      //do something with your array of stats
      //this wont be called until all database calls have been completed
    });
  }
});
于 2013-01-22T19:29:45.463 回答
0

除了上述之外,如果你想将结果返回给应用程序, http://nodeblog.tumblr.com/post/60922749945/nodejs-async-db-query-inside-for-loop

于 2013-09-11T10:26:57.113 回答