请考虑以下代码:
var tick = 0;
setInterval(() => {
console.log(tick);
}, 1000);
setInterval(() => {
tick += 1;
}, 1);
基本上,我希望我的游戏看起来很流畅,所以我每1毫秒更新一次点的位置,这是第二个setInterval中的函数。
在1秒或1000毫秒内,我希望点移动1000像素。但是,它移动大约250像素。
当我运行以下jsfiddle
时,我看到大约250的倍数被打印到控制台。
https://jsfiddle.net/58v74zw4/1/
根据我的观察,我可以通过乘以4来解决它,但感觉很烦人。
造成这种情况的原因是什么,以及对此有何正确解决方法?
答案 0 :(得分:3)
我发现有关JS计时器的最佳文章:https://johnresig.com/blog/how-javascript-timers-work。
由于JavaScript只能在异步事件发生时一次执行一段代码[...]它排队等待以后再执行[...]
这意味着如果有大量代码执行4ms,则间隔处理程序排队最多4ms。
ms | event
----|--------------------------------------------
0 | bigChunk() starts
1 |
2 | interval event fires
3 |
4 | bigChunk() returns
5 | interval handler starts
[...]浏览器[...]等待,直到排队更多时,不再有间隔处理程序排队等等。
这意味着如果有大量代码执行4ms,并且如果间隔设置为每1ms触发一次,则浏览器会在4ms后执行第一个间隔处理程序并删除3个事件。
ms | event
----|--------------------------------------------
0 | bigChunk() starts
1 | interval event fires
2 | interval event dropped
3 | interval event dropped
4 | interval event dropped, bigChunk() returns
5 | interval handler starts
在您的情况下,由于这个原因,可能会丢弃3/4(750/1000)的间隔事件,但也存在与实现相关的原因,例如此处描述的连续调用之间的最小延迟为4ms:https://stackoverflow.com/a/9647221/1636522 (信用:LGSon)。
正如您所看到的,setInterval
在单个线程中使用时不可靠,但是,多线程并不一定会使事情变得更容易。例如,如果间隔处理程序的执行时间是4ms,则需要4个线程,每个线程之间的时移为1ms。
Thread 1 | Thread 2
-------------------------------|-------------------------------
ms | event | ms | event
----|--------------------------|----|--------------------------
0 | interval event fires | 0 |
1 | interval handler starts | 1 | interval event fires
2 | | 2 | interval handler starts
3 | | 3 |
4 | interval handler returns | 4 |
5 | | 5 | interval handler returns
这只是要解决的潜在问题之一。也就是说,如果你仍然想使用多线程,你可以看看Web Workers。我无法帮助,但我从未使用过这个功能: - | https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
另请注意,“大多数浏览器都有60fps [每秒帧数]”(请参阅sunil),这意味着您有近17ms(1000/60)的时间来计算下一帧。因此,每毫秒更新一次游戏状态可能有点过头了: - )