【问题标题】:async foreach call not synchronous node异步 foreach 调用不是同步节点
【发布时间】:2016-07-10 19:49:45
【问题描述】:

我想遍历参与者的一些预测并计算一些点。 要知道玩家获得多少分,我需要调用 mongodb(使用 mongoose)。然后我想保存每个参与者的分数(稍后会这样做)

我正在使用这个异步模块:http://caolan.github.io/async/

var calculateTeamPredictionsPerRound = function (roundId) {
  var roundScores = [];

  predictions.find({}, {}).exec(function (err, predictions) {
    console.log("predictions length: " + predictions.length)
    if (err) return console.error(err);

    async.each(predictions,
      function (prediction) {
        var teamScores = [];
        console.log("team length: " + prediction.Team.length + "deelnemer: " + prediction.Participant.Name)

        async.forEach(prediction.Team, function (player,callback) {
          console.log("for player: " + player.PlayerName + "participant: " + prediction.Participant.Name);

          teamScore.findOne({ RoundId: roundId, 'Player.Id': player.Id }, { Player: { $elemMatch: { Id: player.Id } } }).exec(function (err, player) {
            console.log(player.Player[0].Name);
            var playerScore = new Object;
            playerScore.Name = player.Player[0].Name;
            playerScore.Team = player.Player[0].Team;
            playerScore.Won = setWinScore(player.Player[0]);
            playerScore.Draw = setDrawScore(player.Player[0]);
            playerScore.Played = setPlayedScore(player.Player[0]);
            playerScore.RedCard = setRedCardScore(player.Player[0]);
            playerScore.YellowCard = setYellowCardScore(player.Player[0]);
            playerScore.Assist = setAssistScore(player.Player[0]);
            playerScore.Goals = setGoalScore(player.Player[0]);
            playerScore.OwnGoal = setOwnGoalScore(player.Player[0]);
            playerScore.TotalScore = playerScore.Won + playerScore.Draw + playerScore.Played + playerScore.RedCard + playerScore.YellowCard + playerScore.Assist + playerScore.OwnGoal + playerScore.Goals;
            teamScores.push(playerScore)
          });
          callback();       
        });

      });
  });
};

当我运行此代码时,控制台会显示:

team length: 11 participant: test   
for player: a participant: test  
for player: b participant: test  
for player: c participant: test  
for player: d participant: test  
for player: e participant: test  
for player: f participant: test  
for player: g participant: test  
for player: h participant: test  
for player: i participant: test  
for player: j participant: test  
for player: k participant: test  
team length: 11participant: test2  
for player: a participant: test2  
for player: b participant: test2  
for player: c participant: test2  
for player: d participant: test2  
for player: e participant: test2  
for player: f participant: test2  
for player: g participant: test2  
for player: h participant: test2  
for player: i participant: test2  
for player: j participant: test2  
for player: k participant: test  
a  
b  
c  
d  
e  
f  
g  
h  
i  
j  
k  
a  
b  
c  
d  
e  
f  
g  
h  
i  
j  
k  

但我想要:

team length: 11participant: test  
for player: a participant: test  
a  
for player: b participant: test  
b  

【问题讨论】:

    标签: node.js mongodb async.js


    【解决方案1】:

    问题在于,在您的 async.forEach 方法中,您使用的 .findOne() 方法也是异步的。

    执行顺序为:

    1. console.log("for player:" + player.PlayerName + "participant:" + prediction.Participant.Name);
    2. findOne()
    3. 回调()

    你调用了异步函数的callback(),没有等待findOne()的回调,即function (err, player) {...}

    将 callback() 移动到 function (err, player) {...} 内,等待 findOne() 在完成异步任务之前执行。

    teamScore.findOne({ RoundId: roundId, 'Player.Id': player.Id }, { Player: { $elemMatch: { Id: player.Id } } }).exec(function (err, player) {
                console.log(player.Player[0].Name);
                var playerScore = new Object;
                playerScore.Name = player.Player[0].Name;
                playerScore.Team = player.Player[0].Team;
                playerScore.Won = setWinScore(player.Player[0]);
                playerScore.Draw = setDrawScore(player.Player[0]);
                playerScore.Played = setPlayedScore(player.Player[0]);
                playerScore.RedCard = setRedCardScore(player.Player[0]);
                playerScore.YellowCard = setYellowCardScore(player.Player[0]);
                playerScore.Assist = setAssistScore(player.Player[0]);
                playerScore.Goals = setGoalScore(player.Player[0]);
                playerScore.OwnGoal = setOwnGoalScore(player.Player[0]);
                playerScore.TotalScore = playerScore.Won + playerScore.Draw + playerScore.Played + playerScore.RedCard + playerScore.YellowCard + playerScore.Assist + playerScore.OwnGoal + playerScore.Goals;
                teamScores.push(playerScore)
                callback();  
              });         
            });
    

    此外,您可以使用callback(playerScore) 代替teamScores.push(playerScore),然后给async.forEach 提供最终回调,当所有任务完成时,将使用包含所有playerScores 的数组调用该回调。

    如果 async.forEach 是 this 模块,我不确定你为什么需要它,因为你所有的任务都是异步的。它不会自动使teamScore.findOne() 同步,您仍然必须使用var done = this.async(); 指定异步回调并在findOne() 完成时调用它,但您也可以只使用常规的async.each()。

    【讨论】:

    • 好吧,我只是糊涂了,因为 async.forEach 不是该模块的一部分,只有 async.each。解决方案应该是一样的。
    • forEacheach 的别名
    猜你喜欢
    • 2017-02-10
    • 2018-06-24
    • 2020-03-30
    • 1970-01-01
    • 2017-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-27
    相关资源
    最近更新 更多