在javascript中对代码段进行排队?

在javascript中对代码段进行排队?,javascript,queue,Javascript,Queue,我需要对代码片段进行排队,并在给定的时间(每秒一次)执行它们。这些片段实际上是玩家的动作,如跳跃()、攻击()、行走('left')等 当用户按下某个键时,我需要将其操作排队,并每秒执行一次所有操作 目前,我的方法是将每个代码段添加到一个数组中,并使用eval()对其进行循环。这是我的代码: var queue = []; // On player or AI action queue.push('attack()'); // Could be walk('left'), jump() etc

我需要对代码片段进行排队,并在给定的时间(每秒一次)执行它们。这些片段实际上是玩家的动作,如跳跃()、攻击()、行走('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 = [];
var队列=[];
//论玩家或人工智能动作
queue.push('attack()');//可能是步行('left')、跳跃()等。
//论新框架
对于(var i=0;i这是可怕的-
eval
是邪恶的。相反,使用:

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

为您的附加查询编辑

在您编写的代码中,这应该已将变量捕获到闭包中;如果您更改变量,则该值将是您在执行它时得到的值。如果您得到了
未定义的
,我猜您稍后在某处执行了
closerEnemy=undefined
。例如,当人们试图将单击处理程序绑定到循环中的多个元素,并在处理程序中使用循环计数器-处理程序捕获计数器而不是其值,并始终在以后计算元素数(循环完成时留下的最后一个值)

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

(function(capturedCloserEnemy) {
  queue.push(function() {
    attack(capturedCloserEnemy);
  });
})(closerEnemy);
(变量的名称不同只是为了可读性;它们的名称可以相同,这并不重要,因为阴影。)

这很可怕-
eval
是邪恶的。相反,使用:

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

为您的附加查询编辑

在您编写的代码中,这应该已将变量捕获到闭包中;如果您更改变量,则该值将是您在执行它时得到的值。如果您得到了
未定义的
,我猜您稍后在某处执行了
closerEnemy=undefined
。例如,当人们试图将单击处理程序绑定到循环中的多个元素,并在处理程序中使用循环计数器-处理程序捕获计数器而不是其值,并始终在以后计算元素数(循环完成时留下的最后一个值)

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

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

(变量的名称不同只是为了可读性;它们的名称可以相同,这并不重要,因为阴影。)

您的方法的问题是:

  • 您正在使用eval

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

  • 您正在使用循环

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

  • 为了解决这两个问题,为什么不将对要执行的函数的引用推送到队列中。此外,为了防止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);
    

    您的方法的问题在于:

  • 您正在使用eval

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

  • 您正在使用循环

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

  • 为了解决这两个问题,为什么不将对要执行的函数的引用推送到队列中。此外,为了防止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);
    

    以这种方式使用
    eval
    并没有实际的“风险”,但这当然是错误的。我知道了,但当我想用参数(如attack('up'))将函数排队时会发生什么?没有实际的“风险”以这种方式使用
    eval
    ,但这当然是错误的。我知道了,但当我想用参数(如攻击('up')对函数进行排队时会发生什么?这非常有效,我已经为玩家操作实现了。只是问一个问题,当存储在变量中时,如何将值传递给参数?例如:
    closerEnemy=1;queue.push(函数(){attack(closerEnemy);})
    。稍后调用函数而不是简单地传递1时,它会检查未定义的closerEnemy。@Liso22:更新了您进一步问题的答案。这非常有效。我已经为玩家操作实现了。只是一个问题,当存储在变量中时,如何将值传递给参数?例如:
    closerEnemy=1;queue.push(function(){attack(closerEnemy);});
    。稍后调用该函数而不是简单地传递1时,它会检查未定义的closerEnemy。@Liso22:更新了对进一步问题的回答