异步JavaScript解决方案
Asynchronous JavaScript workarounds
我正在用MEANjs做一些工作,以帮助获得一些经验,我遇到了Mongoose的异步函数调用问题。我不得不构建一些变通方法,因为我一心想以同步的心态编码。我做错了吗?
示例1:在异步回调结束时调用下一个动作
例如,假设有一款JavaScript游戏(MEANjs)拥有服务器端战斗代码。此代码将抓取任何具有战斗命令的AI敌人实体(如攻击,射击火球等)并处理这些命令。然而,需要发生的第一件事是查找MongoDB的可用能力列表,以便我们知道这些战斗命令需要做什么。例如,如果敌人想要执行他们的"喷火IV"技能,返回的信息会让我们知道这造成了多少伤害,等等。
这需要调用Mongoose的模型。找出哪个是异步调用。回调将填充一个对象,其中包含所有稍后可以在战斗命令处理器中使用的能力信息。(这是麻烦的地方)。
一旦模型。find的回调已经被调用,数据将被存储,processCombat()函数将在这个回调结束时执行。没问题,对吧,这是最佳实践吗?在过去,我只是在调用这种类型的异步调用后放置一个setTimeout,以确保对象被填充,但这似乎是一个糟糕的设计。
示例2:将数据传递给迭代调用的异步方法
想象现在你在这个战斗处理器方法中。你有一个模型。Find来获取必须处理的敌人集合,在Find的回调中,你必须执行一个模型。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!
});
}
});
重要的部分是填充enemyList,然后在异步回调中使用它。很有可能,因为findOne是异步的,在第一个findOne回调执行时,enemyList将被完全填充,但尽管如此,它不需要被完全填充以有效执行(即回调中使用的目标对象将在执行findOne时可用)。一旦findOne被执行,它就会遍历敌人列表以找到自己尚未被处理的playerID——记住多个敌人可以针对同一个玩家,所以除了简单地查找playerID外,还需要一个处理过的变量。
有更好的方法吗?
一个警告:如果多个回调同时被调用怎么办?可以创建一个竞争条件,其中多个实例在同一行上,因此使用已处理的变量不会100%完美。
(抱歉,如果这是一个疯狂的问题,但这种类型的编程是奇怪的,我觉得我是在设计反对它,而不是与它,所以我在寻找见解)
在这种情况下,我会将过程分解为几个返回承诺的函数,然后将它们链接在一起。
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);
});
}
- 在Python中抓取javascript渲染的文本的最快解决方案
- 在IE8和其他带有javascript的浏览器中获取正文类的标准解决方案是什么
- 是否有用于CSS浏览器支持新功能的javascript解决方案
- Javascript全局变量简单解决方案
- JavaScript/HTML 错误的解决方案
- Javascript Learnstreet Email Interpreter 替代解决方案
- 正在寻找与以下jQuery解决方案等效的javascript解决方案
- JavaScript没有'JSP页面重定向后无法工作..任何解决方案
- 在两个解决方案中引用通用的Javascript文件
- 用于回文变位的JavaScript解决方案
- windows中的Javascript巨大日期错误..解决方案
- 比许多使用JavaScript的循环迭代更有效的解决方案
- 为静态类型检查注释javascript的好解决方案是什么
- “稍后提醒我”/“快速事件”JavaScript解决方案
- Jquery/Javascript 解决方案,用于将 wiki 文本转换为 HTML,反之亦然
- 适用于 IE8 的子像素舍入 JavaScript/jQuery 解决方案,用于具有百分比宽度的表格单元格
- 解析器错误(Javascript初学者寻找解决方案)
- 在 Javascript 中模拟“IN”运算符以简化冗余逻辑 OR 的最佳解决方案是什么?
- 解决方案 用于使用 javascript 获取 IIS 服务器虚拟目录路径
- Jquery解决方案/ javascript函数分配变量