簡體   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