如何在javascript中创建一个准确的计时器?
2022-08-30 04:19:02
我需要创建一个简单但准确的计时器。
这是我的代码:
var seconds = 0;
setInterval(function() {
timer.innerHTML = seconds++;
}, 1000);
在正好3600秒后,它打印了大约3500秒。
为什么它不准确?
如何创建准确的计时器?
我需要创建一个简单但准确的计时器。
这是我的代码:
var seconds = 0;
setInterval(function() {
timer.innerHTML = seconds++;
}, 1000);
在正好3600秒后,它打印了大约3500秒。
为什么它不准确?
如何创建准确的计时器?
为什么它不准确?
因为您正在使用 或 。它们不能被信任,它们没有准确性保证。它们被允许任意滞后,并且它们不会保持恒定的步伐,而是倾向于漂移(如您所观察到的)。setTimeout()
setInterval()
如何创建准确的计时器?
请改用 Date
对象来获取(毫秒)准确的当前时间。然后,将逻辑基于当前时间值,而不是计算执行回调的频率。
对于简单的计时器或时钟,请显式跟踪时差:
var start = Date.now();
setInterval(function() {
var delta = Date.now() - start; // milliseconds elapsed since start
…
output(Math.floor(delta / 1000)); // in seconds
// alternatively just show wall clock time:
output(new Date().toUTCString());
}, 1000); // update about every second
现在,这存在可能跳跃值的问题。当间隔滞后一点并在 、 、 、 毫秒后执行回调时,您将看到第二个计数 、 、 、 、 (!)。因此,建议更频繁地更新,例如大约每100毫秒更新一次,以避免此类跳跃。990
1993
2996
3999
5002
0
1
2
3
5
但是,有时您确实需要一个稳定的间隔来执行回调而不会漂移。这需要更高级的策略(和代码),尽管它支付得很好(并且注册的超时更少)。这些被称为自调整计时器。在这里,与预期的间隔相比,每个重复超时的确切延迟都适应实际经过的时间:
var interval = 1000; // ms
var expected = Date.now() + interval;
setTimeout(step, interval);
function step() {
var dt = Date.now() - expected; // the drift (positive for overshooting)
if (dt > interval) {
// something really bad happened. Maybe the browser (tab) was inactive?
// possibly special handling to avoid futile "catch up" run
}
… // do what is to be done
expected += interval;
setTimeout(step, Math.max(0, interval - dt)); // take into account drift
}
我只是在Bergi的答案(特别是第二部分)的基础上进行一点构建,因为我真的很喜欢它完成的方式,但是我希望可以选择在计时器启动后停止计时器(就像几乎一样)。所以。。。我已经把它包装成一个构造函数,这样我们就可以用它做“客观”的事情。clearInterval()
好吧,所以你复制/粘贴它...
/**
* Self-adjusting interval to account for drifting
*
* @param {function} workFunc Callback containing the work to be done
* for each interval
* @param {int} interval Interval speed (in milliseconds)
* @param {function} errorFunc (Optional) Callback to run if the drift
* exceeds interval
*/
function AdjustingInterval(workFunc, interval, errorFunc) {
var that = this;
var expected, timeout;
this.interval = interval;
this.start = function() {
expected = Date.now() + this.interval;
timeout = setTimeout(step, this.interval);
}
this.stop = function() {
clearTimeout(timeout);
}
function step() {
var drift = Date.now() - expected;
if (drift > that.interval) {
// You could have some default stuff here too...
if (errorFunc) errorFunc();
}
workFunc();
expected += that.interval;
timeout = setTimeout(step, Math.max(0, that.interval-drift));
}
}
告诉它该做什么等等...
// For testing purposes, we'll just increment
// this and send it out to the console.
var justSomeNumber = 0;
// Define the work to be done
var doWork = function() {
console.log(++justSomeNumber);
};
// Define what to do if something goes wrong
var doError = function() {
console.warn('The drift exceeded the interval.');
};
// (The third argument is optional)
var ticker = new AdjustingInterval(doWork, 1000, doError);
// You can start or stop your timer at will
ticker.start();
ticker.stop();
// You can also change the interval while it's in progress
ticker.interval = 99;
我的意思是,无论如何,它对我有用。如果有更好的方法,莱姆知道。