准确的 Javascript 计时器

Accurate Javascript Timer

我正在尝试构建一个准确的倒数计时器,以显示剩余的分钟数和秒数。我尝试了两种方法。方法 1 使用 setTimer 函数并计算漂移。对于这种方法,一些值被跳过,一些值被重复。方法 2 会产生所有必要的值,但这些值不会以均匀的间隔打印到屏幕上(在 repl.it 中测试)。我怎样才能制作一个既准确又能打印所有值的计时器?

方法一:

function countTime(duration) {
     var expected = 1;
     var secsLeft;
     var startT = new Date().getTime();
     var oneSecond = 1000;
     var expected = startT + oneSecond;

     window.setTimeout(step, oneSecond);

     function step() {
         var nowT = new Date().getTime();
         var drift = nowT - expected;

         if (drift > oneSecond) {
             console.log("drift is over 1 second long!");
         }

         console.log('drift is ' + drift);
         var msDelta = nowT - startT;
         var secsLeft = duration - Math.floor(msDelta / 1000);
         console.log("secsLeft" + secsLeft);

         if (secsLeft === 0) {
             ++count;
             console.log("cleared");

         } else {

             expected += oneSecond;
             setTimeout(step, Math.max(0, oneSecond - drift));
         }
     }
 }
 countTime(60);

方法 2:

function countTime(duration) {
     var expected = 1;
     var secsLeft;
     var inter;
     var startT = new Date().getTime();

     inter = setInterval(function() {
         //change in seconds
         var sChange = Math.floor((new Date().getTime() - startT) / 1000);

         if (sChange === expected) {
             expected++;
             secsLeft = duration - sChange;
             console.log("seconds Left" + secsLeft);
         }

         if (secsLeft === 0) {
             window.clearInterval(inter);
             console.log("cleared");
         }
     }, 100);
 }
 countTime(60);
function(){
  date = get the date
  curSeconds = compute the number of seconds to be displayed
  if(oldSeconds!=curSeconds) then refresh display and do  oldSeconds = curSeconds;     
}

经常调用此函数,调用次数越多,您的计时器就会越准确。我建议你使用 requestAnimationFrame() 而不是 setTimout() 它将被调用每秒 60 次(周期 16ms)因为它是大多数显示器的刷新率,它是最大可见 "accuracy"。当页面不可见时也不会调用它。

简单、干净、长时间不漂移。

它也处理一段时间不被调用。

考虑使用 requestAnimationFrame

function countTime(duration) {
    requestAnimationFrame(function(starttime) {
        var last = null;
        function frame(delta) {
            var timeleft = Math.floor(duration - (delta - starttime)/1000),
                minutes = Math.floor(timeleft/60),
                seconds = timeleft%60;
            if( timeleft > 0) {
                if( last != timeleft) {
                    console.log("Time left: "+minutes+"m "+seconds+"s");
                    last = timeleft;
                }
                requestAnimationFrame(frame);
            }
        }
        frame(starttime);
    });
}
countTime(60);

这将精确到浏览器本身的帧率:)