javascript setInterval 计时慢慢偏离保持准确

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8173580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 02:32:10  来源:igfitidea点击:

setInterval timing slowly drifts away from staying accurate

javascript

提问by Alex Wayne

It seems that when I setIntervalfor 1000ms, it actually fires the function every 1001ms or so. This results in a slow temporal drift the longer its running.

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

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);

When run this shows the inaccuracy immediately.

运行时,这会立即显示不准确。

  • 0ms
  • 1ms
  • 2ms
  • 3ms
  • 4ms
  • 5ms
  • 5ms
  • 7ms
  • 8ms
  • 9ms
  • 9ms
  • 10ms
  • 0ms
  • 1ms
  • 2ms
  • 3ms
  • 4ms
  • 5ms
  • 5ms
  • 7ms
  • 8ms
  • 9ms
  • 9ms
  • 10ms

See it for yourself: http://jsfiddle.net/zryNf/

自己看看:http: //jsfiddle.net/zryNf/

So is there a more accurate way to keep time? or a way to make setIntervalbehave with more accuracy?

那么有没有更准确的计时方法呢?或者一种使setInterval行为更准确的方法?

采纳答案by Alex Wayne

I think I may have figured out a solution. I figured, if you can measure it you can compensate for it, right?

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

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

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();

result varies a bit but here's a recent run:

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

0ms
7ms
2ms
1ms
1ms
1ms
2ms
1ms
1ms
1ms

So if it gets called 1ms, 2ms or even 10ms later than it should the next call is scheduled to compensate for that. As long as inaccuracy is only per call, but the clock should never lose time, then this should work well.

因此,如果它在 1 毫秒、2 毫秒甚至 10 毫秒后被调用,则应该安排下一次调用来补偿它。只要不准确只是每次调用,但时钟不应该浪费时间,那么这应该可以正常工作。



And now I wrapped this up a global accurateIntervalfunction which is a near drop in replacement for setInterval. https://gist.github.com/1d99b3cd81d610ac7351

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

回答by Johnny Craig

with a bit of googleing, you will see thatsetIntervaland settimeoutboth will not execute the code at the exact specified time you tell it. with setInterval(f,1000);it will wait AT LEAST 1000MS before it executes, it will NOT wait exactly 1000MS. Other processes are also waiting for their turn to use the CPU, which causes delays. If you need an accurate timer that times at 1 second. I would use a shorter interval, like 50MS and compare it to the start time. I wouldnt go under 50MS though because browsers have a minimum interval

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

here are a few references:

这里有一些参考:

"In order to understand how the timers work internally there's one important concept that needs to be explored: timer delay is not guaranteed. Since all JavaScript in a browser executes on a single thread asynchronous events (such as mouse clicks and timers) are only run when there's been an opening in the execution. This is best demonstrated with a diagram, like in the following:" taken from: http://css.dzone.com/news/how-javascript-timers-work

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

"Chrome and Chromium provide an interval that averages just over 41 milliseconds, enough of a difference for the second clock to be visibly slower in well under a minute. Safari comes in at just under 41ms, performing better than Chrome, but still not great. I took these readings under Windows XP, but Chrome actually performed worse under Windows 7 where the interval averaged around 46ms." taken from: http://www.goat1000.com/2011/03/23/how-accurate-is-window.setinterval.html

“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

回答by mVChr

Here's another autocorrecting interval. The interval is set to a shorter time period and then it waits until it's at least a second later to fire. It won't always fire exactly 1000ms later (seems to range from 0-6ms delay), but it autocorrects and won't drift.

这是另一个自动更正间隔。间隔设置为较短的时间段,然后等待至少一秒钟后触发。它不会总是在 1000 毫秒后触发(似乎在 0-6 毫秒的延迟范围内),但它会自动更正并且不会漂移。

EDIT:Updated to use recalling setTimeoutinstead of setIntervalotherwise it may do something odd after 1000 or so iterations.

编辑:更新为使用召回setTimeout而不是setInterval在 1000 次左右的迭代后它可能会做一些奇怪的事情。

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

setTimeout(f, 990);

Run demo

运行演示

回答by Phrogz

I don't see a drift nearly as large as your script is reporting:
http://jsfiddle.net/hqmLg/1/

我没有看到几乎和你的脚本报告一样大的漂移:http:
//jsfiddle.net/hqmLg/1/

I'm leaving that script running. Right now (Chrome, Win 7) I see:

我要让那个脚本继续运行。现在(Chrome,Win 7)我看到:

240 calls in 240.005s is 0.99979 calls/second

240.005s 中的 240 个调用是 0.99979 个调用/秒

Indeed, I've seen the drift go up to .007s and then down to .003s. I think your measurement technique is flawed.

事实上,我已经看到漂移上升到 0.007 秒,然后下降到 0.003 秒。我认为你的测量技术有缺陷。

In Firefox I see it drift even more strongly (+/- 8ms either direction) and then compensate in the next run. Most of the time I'm seeing "1.000000 calls/second" in Firefox.

在 Firefox 中,我看到它的漂移更加强烈(任一方向 +/- 8 毫秒),然后在下一次运行中进行补偿。大多数情况下,我在 Firefox 中看到“1.000000 个调用/秒”。