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