Reputation: 540
I have a timer which I am testing, it seems there is a bit of drift between when the minute countdown goes down by 1 and seconds whenever it reaches 59 seconds ()ie every minute:-
How can I alter this so they are both in sync?
my code is the following:-
$(document).ready(function() {
function now() {
return window.performance ? window.performance.now() : Date.now();
}
function tick() {
var timeRemaining = countdown - ((now() - initTick) / 1000);
timeRemaining = timeRemaining >= 0 ? timeRemaining : 0;
var countdownMinutes = Math.floor(timeRemaining / 60);
var countdownSeconds = timeRemaining.toFixed() % 60;
countdownTimer.innerHTML = countdownMinutes + ":" + countdownSeconds;
if (countdownSeconds < 10) {
countdownTimer.innerHTML = countdownMinutes + ":" + 0 + countdownSeconds;
}
if (timeRemaining > 0) {
setTimeout(tick, delay);
}
}
var countdown = 600; // time in seconds until user may login again
var delay = 20; // time (in ms) per tick
var initTick = now(); // timestamp (in ms) when script is initialized
var countdownTimer = document.querySelector(".timer"); // element to have countdown written to
setTimeout(tick, delay);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="timer"></div>
js fiddle: https://jsfiddle.net/robbiemcmullen/cer8qemt/1/
Upvotes: 0
Views: 47
Reputation: 817
Here is a version using setInterval and removing the use of .toFixed () Why do you use an interval of 20ms and not 1 second?
//method for countdown timer
$(document).ready(function() {
function now() {
return window.performance ? window.performance.now() : Date.now();
}
function tick() {
var timeRemaining = countdown - elapsedTime;
var countdownMinutes = Math.floor(timeRemaining / 60);
var countdownSeconds = timeRemaining % 60;
countdownTimer.innerHTML = countdownMinutes + ":" + countdownSeconds;
if (countdownSeconds < 10) {
countdownTimer.innerHTML = countdownMinutes + ":" + 0 + countdownSeconds;
}
++elapsedTime;
return timeRemaining;
}
var countdown = 600;
var elapsedTime = 0;
var timeRemaining;
// countdown: time in seconds until user may login again
//var delay = 20;
// delay: time (in ms) per tick
var initTick = now(); // initTick: timestamp (in ms) when script is initialized
var countdownTimer = document.querySelector(".timer");
// countdownTimer: element to have countdown written to
var interval = setInterval(function() {
if(tick() <= 0) {
clearInterval(interval);
}
}, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="timer"></div>
js fiddle https://jsfiddle.net/ud3wm8t1/
Upvotes: 0
Reputation: 28611
The issue is the precision is not the same for minutes and seconds.
You need to round to the nearest second before /60
/ %60
.
Consider: exactly 9 mins remaining:
var x = 540;
console.log(x.toFixed() % 60, Math.floor(x / 60));`
Output is: (0,9)
Then consider the call 20 ms later:
var x = 539.980;
console.log(x.toFixed() % 60, Math.floor(x / 60));
the output is now: (0, 8).
So the seconds haven't changed (yet) but the minute does.
Upvotes: 2