setInterval计时缓慢偏离准确

Ale*_*yne 22 javascript

似乎当我setInterval持续1000ms时,它实际上每1001ms左右触发一次该功能.这导致运行时间越长,时间漂移越慢.

var start;
var f = function() {
    if (!start) start = new Date().getTime();
    var diff = new Date().getTime() - start;
    var drift = diff % 1000;
    $('<li>').text(drift + "ms").appendTo('#results');
};

setInterval(f, 1000);
Run Code Online (Sandbox Code Playgroud)

运行时,立即显示不准确.

  • 0毫秒
  • 1毫秒
  • 2MS
  • 为3ms
  • 4ms的
  • 5ms的
  • 5ms的
  • 7毫秒
  • 8ms的
  • 9ms的
  • 9ms的
  • 10毫秒

亲眼看看:http://jsfiddle.net/zryNf/

那么有更准确的方法来保持时间吗?还是一种setInterval更准确的表现方式?

Ale*_*yne 14

我想我可能已经找到了解决方案.我想,如果你可以测量它,你可以补偿它,对吧?

http://jsfiddle.net/zryNf/9/

var start;
var nextAt;

var f = function() {
    if (!start) {
        start = new Date().getTime();
        nextAt = start;
    }
    nextAt += 1000;

    var drift = (new Date().getTime() - start) % 1000;    
    $('<li>').text(drift + "ms").appendTo('#results');

    setTimeout(f, nextAt - new Date().getTime());
};

f();
Run Code Online (Sandbox Code Playgroud)

结果有所不同,但这是最近的一次运行:

0ms
7ms
2ms
1ms
1ms
1ms
2ms
1ms
1ms
1ms
Run Code Online (Sandbox Code Playgroud)

因此,如果它被调用1ms,2ms甚至晚10ms,那么下一次调用将被安排来补偿.只要每次通话都不准确,但时钟永远不会浪费时间,那么这应该运作良好.


现在我把它包装成一个全局accurateInterval函数,这个函数几乎可以替代setInterval. https://gist.github.com/1d99b3cd81d610ac7351

  • 一个警告:夏令时.你要么让一帧滞后一小时("弹簧前进"),要么让帧尽快发射(负超时间隔)一整小时("后退"). (2认同)

Joh*_*aig 8

有一点googleing,你会看到,setInterval并且settimeout两个都不会在你告诉它的确切时间执行代码.使用setInterval(f,1000);它会在执行前等待至少1000MS,它不会等到1000MS.其他进程也在等待轮到他们使用CPU,这会导致延迟.如果你需要一个精确的计时器,时间为1秒.我会使用较短的间隔,如50MS,并将其与开始时间进行比较.我不会低于50MS,因为浏览器有最小间隔

这里有一些参考:

"为了理解定时器如何在内部工作,需要探索一个重要的概念:定时器延迟不能得到保证.由于浏览器中的所有JavaScript都在单个线程上执行,因此只运行异步事件(例如鼠标点击和定时器)当执行中有一个开放时.这最好用图表来证明,如下所示:"取自:http://css.dzone.com/news/how-javascript-timers-work

"Chrome和Chromium提供的平均间隔刚好超过41毫秒,第二个时钟的差异足以在一分钟内显着降低.Safari的亮度不到41毫秒,表现优于Chrome,但仍然不是很好.我在Windows XP下读取了这些读数,但Chrome实际上在Windows 7下表现更差,平均间隔约为46毫秒." 取自:http: //www.goat1000.com/2011/03/23/how-accurate-is-window.setinterval.html