在javascript中排队一个片段?

时间:2012-12-20 05:51:59

标签: javascript queue

我需要对片段进行排队并在给定时间(每秒一次)执行所有片段。片段实际上是玩家动作,如jump(),attack(),walk('left')等。

当用户按下某个键时,我需要将其操作排队并每秒执行一次所有操作。

现在,由于缺乏更好的想法,我的方法是将每个片段添加到数组并使用eval()循环遍历它。这是我的代码:

var queue = [];

// On player or AI action
queue.push('attack()'); // Could be walk('left'), jump() etc.

// On new frame
for(var i=0;i<queue.length;i++){
  eval(queue[i]);
  }
queue = [];

我确信我的方法很糟糕,但我想澄清一下我想做什么,我想这样的问题并不是那么罕见。任何信息/想法?

2 个答案:

答案 0 :(得分:3)

可怕 - eval是邪恶的。相反,请使用closures

var queue = [];

queue.push(function() { attack(); });

while (queue.length) {
    queue.shift().call();
}

这是一般情况,但在这种情况下可以简化:function() { attack(); }是一种更复杂,更慢的方式来编写attack,因此queue.push(attack)也可以正常工作(如果您在某处可以访问function attack() { ... }。显然,如果您的函数采用参数(或者更确切地说,如果每个函数采用不同的参数;您可以在call(thisobj, param)调用中提供统一参数列表),则不能这样做。

编辑以获取其他查询:

在您编写的代码中,这应该已将变量捕获到闭包中;如果更改变量,那么该值将是您执行时获得的值。如果你有undefined,我猜你以后会在某个地方执行closerEnemy = undefined。例如,当人们尝试将单击处理程序绑定到循环中的多个元素,并在处理程序中使用循环计数器时,这是常见的错误来源 - 处理程序捕获计数器而不是其值,并且稍后将总是评估到元素的数量(循环结束时剩下的最后一个值)。

要捕获值而不是变量,请使用此技巧:

(function(capturedCloserEnemy) {
  queue.push(function() {
    attack(capturedCloserEnemy);
  });
})(closerEnemy);

(变量的名称不同只是为了便于阅读;它们都可以被命名为相同而且无关紧要,因为阴影。)

答案 1 :(得分:1)

您的方法存在的问题是:

  1. 您正在使用eval

    您已经听说过使用eval的风险。如果没有,请检查this document from MDN

  2. 您正在使用循环

    使用循环时,JavaScript会尝试尽快完成循环。这将导致UI中的阻塞。这也意味着当您以这种方式开始循环时,您的动画将仅显示在第一个动画处移动,冻结,并在队列中的最后一个动画结束。

  3. 作为这两个问题的补救措施,为什么不向队列推送对您要执行的函数的引用。另外,为了防止UI阻塞,请使用计时器:

    var queue = [];
    
    //actions as functions
    function attack(params){...}
    function block(params){...}
    function walk(params){...}
    
    //our animation timer
    var animationTimer = setInterval(function(){
        //remove the action from the queue and execute
        var nextAction = queue.shift();
        //if we shifted something, execute
        if(nextAction){
            nextAction.call();
        }
    },1000);
    
    //to insert into the queue, push the reference of the function instead.
    queue.push(attack);