js定时器优化

在js中如果打算使用setInterval进行倒数,计时等功能,往往是不准确的,因为setInterval的回调函数并不是到时后立即执行,而是等系统计算资源空闲下来后才会执行.而下一次触发时间则是在setInterval回调函数执行完毕之后才开始计时,所以如果setInterval内执行的计算过于耗时,或者有其他耗时任务在执行,setInterval的计时会越来越不准,延迟很厉害.

先看以下两看计时器

   setTimeout版

function test(){
  count += 1;
  console.log(`第${count}次开始 ${getTime.now() - startTime}  ID:${t}`); // 显示开始时间
 
  console.log(`第${count}次结束 ${getTime.now() - startTime}`); // 显示结束时间
  
  //count<1000 && setTimeout(test,500);  //这样写没有ID
  if(count<1000) t=setTimeout(test,500);  //这样写没有ID
}
 
let count = -1;
let getTime = window.performance;
let startTime = getTime.now();
var t;

test(); // 300ms间隔

运行结果

误差很大,原因js是单线程,而setTimeout两次时间间隔为timer执行时间+interval延时时间,久而久之积累的误差就大了

setInterval版
function sleep(time) {
  let startTime = window.performance.now();
  while (window.performance.now() - startTime < time) {}
}

function test(){
    count++;
    console.log(`第${count}次开始 ${getTime.now() - startTime}`); 
    // 显示开始时间
    //sleep(100); // 程序滞留500ms
    console.log(`第${count}次结束 ${getTime.now() - startTime}`); // 显示结束时间
    count>1000 && clearInterval(t);
}

let count = 0;
let getTime = window.performance;
let startTime = getTime.now();

var t = setInterval(test , 500); // 300ms间隔

最后结果:

 测了两次结果差很多,可能应该是第一次我切出当前页的原因,已至getTime.now();出错,从第二个结果看,还是很精准的,但是,

第一种写法:

1
2
3
4
funciton xxx(){
//函数代码,此处执行时间约20毫秒
setTimeout(xxx,10)
}

第二种写法:

1
2
3
4
funciton xxx(){
//函数代码,此处执行时间约20毫秒
}
setInterval(xxx,10)

第一种写法中,只有执行完20ms的代码后,再等10ms才会开始下一个循环;

第二种写法中,无论有没有执行完20ms的代码,10ms后都会开始下一个循环

setTimeout优化版:

var startTime0 = new Date().getTime();
let count = 0;
let getTime = window.performance;
let startTime = getTime.now();
var t;
//setTimeout(test,500); // 300ms间隔

setTimeout(function () {
   count += 1;
   console.log(`第${count}次开始 ${getTime.now() - startTime}`); 
   // 显示开始时间
   //sleep(500); // 程序滞留500ms
  

   var offset = getTime.now() - (startTime + count * 500);
    var nextTime = 500 - offset;
   //console.log(nextTime);
    if (nextTime < 0) nextTime = 0;
    console.log(`第${count}次结束 ${getTime.now() - startTime}        下次延时:${nextTime}`); // 显示结束时间
    if(count<1000){setTimeout(arguments.callee, nextTime);}
            
  }, 500)

setTimeout优化后的结果

 setTimeout优化说明:

1、最大的特点就是动态修正当前触发的延迟时间。

2、为什么选择setTimeout,因为setTimeout更方便调节延迟时间。

3、使用performance.now()是当前时间与performance.timing.navigationStart的时间差,以微秒(百万分之一秒)为单位的时间,与 Date.now()-performance.timing.navigationStart的区别是不受系统程序执行阻塞的影响,因此更加精准。关于performance的更多内容 

4、第二个setTimeout()调用使用了agrument.callee 来获取当前实行函数的引用,并设置另外一个新定时器。这样做可以保证在代码执行完成前不会有新的定时器插入。(来自

相关链接:https://blog.csdn.net/acm765152844/article/details/51298915

原文地址:https://www.cnblogs.com/7qin/p/10225220.html