This is almost certainly a problem with WebKit.
Problem
When you use setTimeout , you create a "timer" with two properties:
- Current timestamp + preset delay
- Callback for fire once when the system time is more than a timestamp.
You can imagine a naive setTimeout implementation that looks something like this:
var timers = []; function setTimeout(callback, delay) { var id = timers.length; timers[id] = { callback: callback, timestamp: Date.now() + delay } return id; }
This will simply create a timer and add it to the list. Then, at each tick, JS runtime checks these timers and makes callbacks for running ones:
var now = Date.now(); for(var id in timers) { var timer = timers[id]; if(timer && timer.timestamp < now) { callback(); delete timers[id]; } }
Given this implementation, imagine that now change the system time (i.e. Date.now() in the above examples) to a value in the past - the timer timestamp will still be set relative to the previous system time (i.e., in future).
The same problem exists with setInterval , which (provided that the correct code in WebKit) is implemented using setTimeout .
Unfortunately, this means that any call to setTimeout or setInterval will suffer.
Decision
Alternatively, you can use the beautiful window.requestAnimationFrame method to call back each tick. I did not test this at all, but it should continue to shoot at every tick, regardless of the system time.
As a bonus, every time it launches a callback, you pass the current timestamp as a parameter. By tracking the previous timestamp passed to your callback, you can easily detect backward changes in system time:
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);
Conclusion
This may not be big news for you, but you should probably rewrite your entire application to use requestAnimationFrame anyway - it seems a lot more suitable for your needs:
var onNextFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame; var dateElem = document.getElementById('date'); var updateDate = function(timestamp) { dateElem.textContent = new Date(); onNextFrame(updateDate); }; onNextFrame(updateDate);