繁体   English   中英

WebKit setInterval和系统时间更改

[英]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实现。

不幸的是,这意味着setTimeoutsetInterval 任何调用都会受到影响。

解决方案

或者,您可以使用可爱的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM