使用setTimeout在javascript中超时不一致?

时间:2011-09-22 02:01:50

标签: javascript html5 canvas

我正在制作游戏。游戏有1个主循环:

//draws a new frame and game logic
function draw()
{
   player.gameTick();
   game.gameTick();

   lastTime=newTime; 

   background.draw(ctx);
   player.draw(ctx);
   enemies.draw(ctx);
   setTimeout(draw,50);
}

通常情况下运行正常,我向#console报告了20fps。然而,偶尔会出现fps达到> 125的情况。 (意思是在前一次调用后不到50毫秒时调用draw)。当发生这种情况时,游戏开始滞后几秒钟,然后fps又回落。 (这也是反直觉的,为什么更高的fps导致滞后?)

无论如何,有谁知道为什么会这样?

是的,我也尝试了setInterval(),同样的事情发生了。 = /

2 个答案:

答案 0 :(得分:2)

JavaScript是单线程的。如果你独立地安排两次50秒的超时,那么它们最终可能会碰撞或接近它,并导致奇怪的处理阻塞一秒钟,然后再将它们自行排除。您应该合并代码并创建一个调用其他两个函数的主循环。这样,您可以确保它们每50毫秒处理一次。

你的流程看起来像这样:

  1. Process1() - >需要一些时间,希望小于50毫秒,但保证是> 0毫秒。
  2. Process1将来为自己设置超时50ms。 Process1的第二次运行将在第一次启动后超过50ms发生。
  3. Process2() - >需要一些时间,大于0毫秒。与Process1相同。
  4. Process2为自己设置超时。同样的规则适用。 Process2的第二次运行将在第一次启动后超过50ms发生。
  5. 理论上,如果Process1需要5ms而Process2需要7ms,则每7次运行Process1或5运行Process2将导致将来50ms的下一次超时设置与下一次运行其他功能的预定时间完全对应。当需要同时处理多个事件的解释器被要求同时处理多个事件时,这种类型的冲突将导致不一致的行为。

    - 编辑您对问题的修订 -

    您将来还会设置两个独立的超时时间为50毫秒。仍然没有办法阻止这些碰撞,我仍然不完全确定你为什么这样接近它。你应该有这样的东西:

    function mainLoop() {
      player.tick();
      game.tick();
      background.draw();
      players.draw();
      enemies.draw();
      setTimeout(mainLoop, 50);
    }
    
    mainLoop()
    

    注意没有重复的setTimeout调用。一切都可以一气呵成。您在所演示代码的两个版本中都会产生冲突。

答案 1 :(得分:0)

此问题是由浏览器javascript计时器限制引起的。当我打开许多标签或在标签之间切换时,我注意到问题变得更加严重。 Chrome的问题较少,很可能是由于标签处于隔离的过程中。

Firefox 7似乎解决了FF的这个问题。