当前位置: 代码迷 >> JavaScript >> 异步JavaScript解决方法
  详细解决方案

异步JavaScript解决方法

热度:25   发布时间:2023-06-05 11:43:28.0

我正在与MEANjs进行一些合作以帮助获得一些经验,并且Mongoose的异步函数调用遇到了问题。 我必须构建变通方法,因为我一心想用同步思维定式进行编码。 我做错了吗?

示例1:在异步回调结束时调用下一步操作

例如,假设有一个具有服务器端战斗代码的JavaScript游戏(MEANjs)。 该代码将捕获具有战斗命令(例如,攻击,射击火球等)的所有AI敌方实体,并处理这些命令。 但是,首先需要做的是从MongoDB查找可用功能列表,以便我们知道这些战斗命令需要做什么。 例如,如果敌人想要执行其“喷火IV”能力,则返回的信息将使我们知道这会造成多大的伤害,等等。

这将需要调用Mongoose的model.find,这是一个异步调用。 回调将使用所有能力信息填充对象,这些信息稍后可在战斗命令处理器中使用。 (这是麻烦的部分)。

一旦调用model.find的回调,将存储数据,并在此回调的末尾执行processCombat()函数。 没问题,对,这是最佳做法吗? 过去,在调用这种类型的异步调用之后,我只是放置了setTimeout以确保填充了该对象,但这似乎是一个糟糕的设计。

示例2:将数据传递给迭代调用的异步方法

想象一下,现在您正在使用这种战斗处理器方法。 您有一个model.find来获取必须处理的敌人集合,并且在该查找的回调中,您必须执行model.findOne来获取该敌人的目标玩家并在其回调中执行某些操作,例如验证战斗命令,改变玩家的健康状况,更新敌人以使其知道自己已经处理了战斗命令,等等。

伪代码:对于准备战斗的每个敌人,1)取得敌人,2)取得其在战斗中瞄准的玩家,3)更新玩家和敌人的数据以完成战斗,即玩家失去一些生命值。

Enemy.find(... function(err,enemies) {
    var enemyList = [];
    for(var i=0; i < enemies.Length; i++) {
        enemyList.push({
          playerID: enemies[i].combatTargetID,
          enemy: enemies[i],
          processed: false
        });

        Player.findOne({_id: enemies[i].combatTargtID}, function(err,player) {
            var enemy = null;
            for(var j = 0; j < enemyList.length; j++) {
                if(player.id === enemyList[j].playerID && enemyList[j].processed === false) {
                    enemy = enemyList[j].enemy;
                    enemyList[j].processed = true;
                    break;
                }
            }
            //do things with enemy and player!
        });
    }
});

重要的部分是填充敌方列表,然后在异步回调中使用它。 由于findOne是异步的,很有可能在执行第一个findOne回调时就完全填充了敌人列表,但是尽管如此,它也不需要完全填充即可有效执行(即,回调将在执行findOne时可用。 一旦执行findOne,就会遍历敌人列表以查找当前尚未处理的自己的玩家ID-请记住,多个敌人可以将同一个玩家作为目标,因此除只需查找玩家ID。

有没有更好的办法?

一个警告:如果同时调用多个回调该怎么办。 可以在同一行上创建多个实例的竞争条件,因此使用处理后的变量并不是100%完美的。

(很抱歉,如果这是一个疯狂的问题,但是这种类型的编程很奇怪,我觉得我是针对它而不是针对它进行设计,所以我正在寻找见识)

在这种情况下,我会将流程分解为几个函数,这些函数返回promise,然后将它们全部链接在一起。

function getEnemies (obj) {
  return new Promise(function (resolve) {
    Enemy.find(... function(err,enemies) {
      if (err) {throw err;}
      obj.enemies = enemies.map(function (enemy) {
        return {
          playerID: enemy.combatTargetID,
          enemy: enemy,
          processed: false
        };
      });
      resolve(obj);
    });
  });
}

function getPlayers (obj) {
  return Promise.all(obj.enemies.map(function (enemy) {
    return new Promise(function (resolve) {
      Player.findOne({_id: enemy.combatTargtID}, function(err,player) {
        if (err) {throw err;}
        enemy.player = player;
        resolve();
      });
    })
  }).then(function () {
    return obj;
  });
}

function doWork() {
  getEnemies()
    .then(getPlayers)
    .then(function (obj) {
      console.log(obj); // do stuff with enemies and players here
    }).catch(function (err) {
      console.log(err, err.stack); 
    });
}
  相关解决方案