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のようなある種のフロー制御です。を使用async.mapすると、DBへのすべての呼び出しを並行して行い、すべてのdb呼び出しが完了した後、使用できる値の配列としてそれらを返すことができます。

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 に答える