js基礎 ---- 為什么定時器時間不准確


一、為什么會出現定時器不准確

  這個其實就得提到js執行機制了,叫做事件循環Eventloop 循環機制中,異步事件 setInterval 到時后會把回調函數放入消息隊列中Event Queue,主線程的宏任務執行完畢后依次執行消息隊列的微任務,等微任務執行完了在循環回來執行宏任務。並且由於消息隊列中存在大量任務,其他任務執行時間就會造成定時器回調函數的延遲,如果不處理則會一直疊加延遲

二、宏任務和微任務

  js可分為同步任務和異步任務,對於同步的任務,我們當然知道按照順序進行執行,但是對於異步的操作,會有一個優先級的執行順序,分別為宏任務和微任務

  宏任務:setTimeout, setInterval, setImmediate, I/O, UI rendering

      宏任務是一個外部腳本文件,一個用戶交互觸發的事件或一個setTimeout調用的回調函數。為了實現單線程這個概念,js有一個宏任務隊列(先進先出),宏任務不斷地創建出來塞到隊尾,js引擎不斷地從隊首取任務出來執行。

  微任務:process.nextTick, Promises, MutationObserver

      微任務是由Promise創建出來的且js中有一個專門的微任務隊列來存儲微任務。微任務的機制是:當執行完一個任務后,只要有微任務就先執行微任務。宏任務和渲染通通排到后面。

                                       

 

 

 

 三、解決方法

    根據定時器最開始時間計算當前時間(回調函數執行時間)與開始時間的誤差,用期望時差減誤差作為下一次任務的時間間隔

      var startTime = new Date().getTime();
      var count = 0;
      //耗時任務
      setInterval(function(){
      var i = 0;
      while(i++ < 100000000);
      }, 0);
      function handle() {
        count++;
        var offset = new Date().getTime() - (startTime + count * 1000);
        var nextTime = 1000 - offset;
        if (nextTime < 0) nextTime = 0;
        setTimeout(handle, nextTime);
        console.log(count + ' --- ' + (new Date().getTime() - (startTime + count * 1000)));
      }
      setTimeout(handle, 1000);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM