2015-09-03 2 views
2

Я пытаюсь создать точный таймер обратного отсчета, который показывает минуты и секунды слева. Я пробовал 2 подхода. Подход 1 использует функцию setTimer и вычисляет дрейф. Для этого подхода некоторые значения пропускаются, а некоторые значения повторяются. Подход 2 дает все необходимые значения, но значения не печатаются на экране равномерно (проверено в repl.it). Как я могу сделать таймер, который является точным и печатает все значения?Точный Javascript Timer

Approach1:

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); 

Approach2:

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); 
+1

Это, вероятно, является кандидатом на 'requestAnimationFrame()'. – jwueller

ответ

1

Рассмотрите возможность использования 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); 

Это будет точно в пределах фреймрейтом самого браузера :)

1
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 раз в секунду (период 16 мс), поскольку это частота обновления большинства дисплеев, это максимальная видимая «точность». Также он не будет вызываться, когда страница не будет видна.

Простой, чистый, без дрейфа в течение длительных периодов времени.

Он также обрабатывается не на время.