There are two methods to get what you want.
- Use a background process (web worker).
- Track the time against a timestamp at the beginning, and show the difference between now and then, instead of incrementing per interval frame.
Web Worker Version
If you can support web workers, then you could use those to run a dedicated background process that supports the type of time frame push you're wanting to do (increment a timer frame by frame in an interval, without a timestamp diff, and keep it accurate).
Here is an example, found on this webpage:
http://frenticb.com/tricks/simple-timer.php
<div class="header">A simple timer:</div>
<div class="timer" id="timer">00:00</div>
<div class="buttons">
<button onclick="startTimer()" id="button1">Start</button>
<button onclick="stopTimer()" id = "button2">Stop</button>
</div>
<script>
var w = null; // initialize variable
// function to start the timer
function startTimer(){
// First check whether Web Workers are supported
if (typeof(Worker)!=="undefined"){
// Check whether Web Worker has been created. If not, create a new Web Worker based on the Javascript file simple-timer.js
if (w==null){
w = new Worker("simple-timer.js");
}
// Update timer div with output from Web Worker
w.onmessage = function (event) {
document.getElementById("timer").innerHTML = event.data;
};
} else {
// Web workers are not supported by your browser
document.getElementById("timer").innerHTML = "Sorry, your browser does not support Web Workers ...";
}
}
// function to stop the timer
function stopTimer(){
w.terminate();
timerStart = true;
w = null;
}
</script>
And the simple.timer.js (note that web workers requires this to be a url):
var timerStart = true;
function myTimer(d0){
// get current time
var d=(new Date()).valueOf();
// calculate time difference between now and initial time
var diff = d-d0;
// calculate number of minutes
var minutes = Math.floor(diff/1000/60);
// calculate number of seconds
var seconds = Math.floor(diff/1000)-minutes*60;
var myVar = null;
// if number of minutes less than 10, add a leading "0"
minutes = minutes.toString();
if (minutes.length == 1){
minutes = "0"+minutes;
}
// if number of seconds less than 10, add a leading "0"
seconds = seconds.toString();
if (seconds.length == 1){
seconds = "0"+seconds;
}
// return output to Web Worker
postMessage(minutes+":"+seconds);
}
if (timerStart){
// get current time
var d0=(new Date()).valueOf();
// repeat myTimer(d0) every 100 ms
myVar=setInterval(function(){myTimer(d0)},100);
// timer should not start anymore since it has been started
timerStart = false;
}
Non-Web Worker Version
And the non-web worker version:
<p id='timer'>0.00</p>
<p id='starter-container'>
<button type='button' id='starter'>Start</button>
<button type='button' id='starter-reset'>Reset</button>
</p>
<script>
(function oab(){ // Keep it local.
var runs = 0,
max_runs = 10000,
speed = 10,
timeout = speed,
start_time = 0,
time = 0,
num_seconds = (30) * 1000,
mark_every = 100,
mark_next = time * speed,
timer_el = document.getElementById('timer'),
starter = document.getElementById('starter'),
reset = document.getElementById('starter-reset');
starter.addEventListener('click', function cl(){
reset_timer();
init_timer();
do_timer();
this.disabled = true;
});
reset.addEventListener('click', function cl(){
runs = max_runs++;
});
function init_timer() {
start_time = new Date().getTime();
time = Math.floor(start_time / speed);
}
function reset_timer() {
runs = 0;
starter.disabled = false;
timer_el.innerText = '0.00';
}
function do_timer(){
init_timer();
(function timer () {
var c_time = new Date().getTime(),
time_diff = c_time - start_time,
c_secs = 0;
runs += 1;
c_secs = (Math.round(time_diff / 10, 3) / 100).toString();
if (c_secs.indexOf('.') === -1) {
c_secs += '.00';
} else if (c_secs.split('.').pop().toString().length === 1 ) {
c_secs += '0';
}
timer_el.innerText = c_secs;
if (c_time >= mark_next) {
console.log(
'mark_next: ' + mark_next,
'mark time: ' + c_time,
'(' + (Math.floor(c_time * .01) * 100).toString().substring(10) + ')',
'precision: ' + (mark_next - c_time) + ')'
);
mark_next = Math.floor((c_time + mark_every) * .01) * 100;
}
if (Math.floor(c_time / speed) > time + 1) {
timeout = speed - ((c_time / speed) - time);
} else if (Math.floor(c_time / speed) < time + 1) {
timeout = speed + (time - Math.floor(c_time / speed));
} else {
timeout = speed;
}
time = Math.floor(new Date().getTime() / speed);
if (runs >= max_runs || time_diff > num_seconds) {
reset_timer();
return;
}
setTimeout(timer, timeout);
})();
}
})();
</script>
http://jsfiddle.net/y3zL84ox/9/