[英]WebKit setInterval and system time change
创建简单任务时遇到以下问题:使用WebKit引擎显示html时钟。 附加要求是处理系统时间更改,并且该更改应在Windows上运行。 我已经使用setInterval达到了这个目的,但是在向后更改系统时间后,它似乎冻结了浏览器。 对我来说,它看起来像WebKit问题。 通过运行以下简单代码,可以轻松地在safari上重现代码:
<p id="date"></p>
setInterval(SetTime, 1000);
function SetTime() {
document.getElementById('date').textContent=new Date();
}
之后,我使用了递归setTimeout调用的另一种方法。 效果一样。
(function loop() {
document.getElementById('date').textContent=new Date();
setTimeout(loop, 1000);
})();
有什么想法为什么会发生以及如何解决这个问题?
WebKit几乎绝对是一个问题。
使用setTimeout
,将创建具有两个属性的“计时器”:
您可以想象一个简单的setTimeout
实现看起来像这样:
var timers = [];
function setTimeout(callback, delay) {
var id = timers.length;
timers[id] = {
callback: callback,
timestamp: Date.now() + delay
}
return id;
}
这将简单地创建一个计时器并将其添加到列表中。 然后,在每个刻度上,JS运行时将检查这些计时器并执行已触发的回调:
var now = Date.now();
for(var id in timers) {
var timer = timers[id];
if(timer && timer.timestamp < now) {
callback();
delete timers[id];
}
}
有了这种实现,想象一下现在将系统时间(即上述示例中的Date.now()
)更改为过去的值-计时器的时间戳仍将相对于先前的系统时间(即将来)进行设置。
setInterval
存在相同的问题(假设WebKit中使用合理的代码)将使用setTimeout
实现。
不幸的是,这意味着setTimeout
或setInterval
任何调用都会受到影响。
或者,您可以使用可爱的window.requestAnimationFrame
方法在每个刻度上执行回调。 我根本没有测试过,但是无论系统时间如何,它应该在每个刻度上继续触发。
另外,每次触发回调时,您都会将当前时间戳作为参数传递。 通过跟踪传递给回调的前一个时间戳,您可以轻松地检测到系统时间的倒退:
var lastTimestamp;
var onNextFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame;
var checkForPast = function(timestamp) {
if(lastTimestamp && timestamp < lastTimestamp) {
console.error('System time moved into the past! I should probably handle this');
}
lastTimestamp = timestamp;
onNextFrame(checkForPast);
};
onNextFrame(checkForPast);
对于您来说,这可能不是个好消息,但是您可能应该重写整个应用程序以使用requestAnimationFrame
似乎更适合您的需求:
var onNextFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame;
var dateElem = document.getElementById('date');
var updateDate = function(timestamp) {
dateElem.textContent = new Date();
onNextFrame(updateDate);
};
onNextFrame(updateDate);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.