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

posted @ 2020-10-10 17:36  有梦想的咸鱼7  阅读(1829)  评论(0编辑  收藏  举报