datetime - Accurate Timers in Vanilla JavaScript -


i work creating timers / stopwatches , i've come upon problem.

when using setinterval();, rather ever accurate. i'm using safari 8, , after 20 seconds, can off +-8 seconds. i'm trying time every 10ms requestframeanimation won't cut because i'm not animating.

i've come following uses date object

var runs = 0,     speed = 10,     timeout = speed,     time = math.floor(new date().gettime() / speed);  function timer () {      runs += 1;      console.log(runs, new date().gettime() / speed);      if (math.floor(new date().gettime() / speed) > time + 1) {         timeout = speed - (math.floor(new date().gettime() / speed) - time);     } else if (math.floor(new date().gettime() / speed) < time + 1) {         timeout = speed + (time - math.floor(new date().gettime() / speed));     } else {         timeout = speed;     }      time = math.floor(new date().gettime() / speed);      settimeout(function () {         timer(); //repeat     }, timeout); }  timer();//starts timer 

except can still have 3 runs within 100 ms (.6, .64, .68) third of speed.

i've seen many solutions on how can achieved other languages such node.js, java, c# , javascript libraries can't seem solve basic problem.

is there i'm missing? what's best way this?

there 2 methods want.

  1. use background process (web worker).
  2. track time against timestamp @ beginning, , show difference between , then, instead of incrementing per interval frame.

web worker version

if can support web workers, use run dedicated background process supports type of time frame push you're wanting (increment timer frame frame in interval, without timestamp diff, , keep accurate).

here example, found on 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 start timer function starttimer(){    // first check whether web workers supported    if (typeof(worker)!=="undefined"){       // check whether web worker has been created. if not, create new web worker based on javascript file simple-timer.js       if (w==null){          w = new worker("simple-timer.js");       }       // update timer div output web worker       w.onmessage = function (event) {          document.getelementbyid("timer").innerhtml = event.data;       };    } else {       // web workers not supported browser       document.getelementbyid("timer").innerhtml = "sorry, browser not support web workers ...";    } }  // function stop timer function stoptimer(){    w.terminate();    timerstart = true;    w = null; } </script> 

and simple.timer.js (note web workers requires url):

var timerstart = true;  function mytimer(d0){    // current time    var d=(new date()).valueof();    // calculate time difference between , 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 10, add leading "0"    minutes = minutes.tostring();    if (minutes.length == 1){       minutes = "0"+minutes;    }    // if number of seconds less 10, add leading "0"    seconds = seconds.tostring();    if (seconds.length == 1){       seconds = "0"+seconds;    }     // return output web worker    postmessage(minutes+":"+seconds); }  if (timerstart){    // 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 has been started    timerstart = false; } 

non-web worker version

and 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 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/


Popular posts from this blog