Reputation: 74
In our application, we have a need for a robust countdown timer. When the timer counts down to zero, we move the user on to the next page.
There are a LOT of questions on here about making a countdown timer in JavaScript. I've weeded through a lot of them, looked at a lot of the code samples, tried a lot of plugins, and all of them fail for this one test case: If you adjust your computers system clock, all of these timers mess up (gain time, lose time, or just freeze). The reason is that most of them base their logic on saving some initial start time and then at some interval (either via setTimeout or setInterval) getting the current time and doing a diff between it and the start time. When you adjust your system time, the "current" time can be an hour or days before your start time, or hours or days later.
So, I've come up with the following code to try to handle these system change scenarios. The main thing I do is check if the "diff" between my start and current is negative (or greater than roughly one hour to handle an automatic daylight savings adjustment) to just use the tick interval as an approximation. Also, reset the start time to be current time on each tick, so that elapsed time is the sum of the time between differences, not just the diff between an initial start time and current time. Anyone see any flaws with this approach?
var timeLeft = 60000, // time left in ms, 1 minute for this example
startTime,
totalElapsedTime = 0,
TICK_INTERVAL = 500; // the setTimeout interval
var timerTick = function () {
var now = new Date(),
elapsedTime = now.getTime() - startTime.getTime();
// if the elapsed time was positive and less than approximately an hour, then add the elapsed time to the total
// otherwise, add the TICK_INTERVAL, which we know is the theoretical minimum between timerTick() calls
totalElapsedTime = (elapsedTime > 0 && elapsedTime < 3590000) ? totalElapsedTime + elapsedTime : totalElapsedTime + TICK_INTERVAL;
// reset start time
startTime = now;
// there is time left, so set up another tick
if (totalElapsedTime < timeLeft) {
// update the html that is displaying remaining time
setTimeout(timerTick, TICK_INTERVAL);
}
else {
// time ran out, so do whatever you do when it runs out
}
}
// start the timer
startTime = new Date();
setTimeout(timerTick, TICK_INTERVAL);
Upvotes: 0
Views: 732
Reputation: 54810
Why does the following not work for you?
var timeleft = 60000,
tick = 1000,
intervalID = window.setInterval(function () {
timeleft = timeleft - tick;
if (timeleft <= 0) {
// clear the interval
clearInterval(intervalID);
// do something
}
}, tick);
Update
Using setTimeout
(this will drift, but probably be ok unless you are using it for animation):
var timeleft = 60000,
tick = 1000;
window.setTimeout(function timerFn() {
timeleft = timeleft - tick;
if (timeleft > 0) {
// set the next timeout
setTimeout(timerFn, tick);
} else {
// do something
}
}, tick);
Upvotes: 1