「JavaScript 定時器」setInterval、setTimeout和requestAnimationFrame淺析

一.常見定時器

咱們常見的定時器有如下兩種

1. window.setTimeout 用於在指定的毫秒數後執行某段既定的代碼
2. window.setInterval 用於每隔一段毫秒數重複執行既定的代碼

這兩個方法均可以經過手工設置時間來設定是多少毫秒後執行這段代碼,或者是每隔多少毫秒執行這段代碼。

雖然咱們期待瀏覽器按照咱們設定的時間精確的執行代碼,可是js卻不能保證代碼能剛好在那個時間點被運行,緣由有兩個。html

  • 大多數瀏覽器並無精確到毫秒級別的觸發事件,例如,咱們設定某個函數在3毫秒後執行,在老版本的IE中,這個函數至少會在15毫秒之後執行。而在現代瀏覽器中,這個數值會短一點,但時間差通常也會超過1毫秒。
  • 第二個緣由與js的運行機制有關,具體見JavaScript 運行機制詳解:再談Event Loop.簡單來講,就是js是一個單線程的解釋器,一段時間只能執行一段代碼,因此運行時分爲主線程和任務隊列兩部分。而咱們在定時器中設置的時間,僅表明1000毫秒後把這個任務插入到任務隊列中,而此時必需要等到主線程的代碼執行完畢,才能執行任務隊列中的定時器的任務(在任務隊列中也有調度,不必定第一個執行當前任務),所以時間是沒法保證的。

2、requestAnimationFrame

那有沒有時間準確的定時器呢?有一種選擇是requestAnimationFrame. 示例以下:api

function animateMe(){
    requestAnimationFrame(function(){
      console.log(new Date());
      animateMe();
    })
}
animateMe();

這個api的原理是在由系統來決定回調函數的執行時機,在每一次系統繪製以前,會主動調用requestAnimationFrame中的回調函數,而頻率也牢牢跟隨瀏覽器的刷新頻率。好比通常電腦的刷新頻率一般爲60Hz,即一秒鐘重繪60次,那麼回調函數就等於1000/60=16.7毫秒被執行一次,而若是刷新頻率變爲75Hz,那麼這個時間就變爲1000/75=13.3毫秒被執行一次。這樣能保證回調函數在每一次繪製的間隔時間內只被執行一次,所以它的時間是可靠的。瀏覽器

3、實戰

光說不練假把式,如今咱們就用上面介紹的三種定時器完成進度條的效果。 函數

1.setIntervaloop

var timer;
$('.runBtn').click(function(){
    clearInterval(timer);
    $('#bar').width(0);
    timer = setInterval(function(){
      if($('#bar').width() < 500){
         $('#bar').width($('#bar').width()+5);
         $('#bar').text($('#bar').width()/5+'%');
      }else{
        clearInterval(timer);
      } 
    },16);
 });

點此預覽效果學習

2.setTimeout.net

var timer;
$('.runBtn').click(function(){
    clearTimeout(timer);
    $('#bar').width(0);
    timer = setTimeout(function fn(){
      if($('#bar').width() < 500){
         $('#bar').width($('#bar').width()+5);
         $('#bar').text($('#bar').width()/5+'%');
         timer = setTimeout(fn,16);
      }else{
        clearTimeout(timer);
      } 
    },16);
 });

點此預覽效果線程

3.requestAnimationFramecode

var timer;
$('.runBtn').click(function(){
    cancelAnimationFrame(timer);
    $('#bar').width(0);
    timer = requestAnimationFrame(function fn(){
      if($('#bar').width() < 500){
         $('#bar').width($('#bar').width()+5);
         $('#bar').text($('#bar').width()/5+'%');
         requestAnimationFrame(fn);
      }else{
        cancelAnimationFrame(timer);
      } 
    });
 });

點此預覽效果htm

4、最後

文章都來自本人的總結,不免有些紕漏,歡迎你們指正。一塊兒學習,一塊兒進步。若是以爲不錯,歡迎點贊收藏嚶嚶嚶~~~

相關文章
相關標籤/搜索