定时器不准的原因:
代码不对导致的定时器不准那肯定不需要过多解释,比较头疼的是因为”被阻塞的任务:如果在setTimeout之前有其他的代码或任务需要执行,并且这些任务的执行时间较长,可能会导致setTimeout的延迟时间被延迟执行或完全被丢弃“这种问题导致的bug在项目里面比较难以复现,但是当大批量用户使用的时候,就会偶然存在定时器不准的问题
解决办法:
1.worker.js
Web Worker为Web内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。此外,他们可以使用XMLHttpRequest
执行 I/O (尽管responseXML
和channel
属性总是为空)。一旦创建, 一个worker 可以将消息发送到创建它的JavaScript代码, 通过将消息发布到该代码指定的事件处理程序(反之亦然)。
Web Worker 的作用就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程不会被阻塞或拖慢
// index.js
let count = 0;
//耗时任务
setInterval(function(){
let i = 0;
while(i++ < 100000000);
}, 0);
// worker
let worker = new Worker('./worker.js')
// worker.js
let startTime = new Date().getTime();
let count = 0;
setInterval(function(){
count++;
console.log(count + ' --- ' + (new Date().getTime() - (startTime + count * 1000)));
}, 1000);
这种方案体验整体上来说还是比较好的,既能较大程度修正计时器也不影响主进程任务.
2.requestAnimationFrame 动画循环
举例,使用requestAnimationFrame写一个一秒的延时器代替setTimeOut
// 使用requestAnimationFrame代替定时器解决定时器的异常问题
// callback指的是当一秒之后 你需要让这个方法执行的函数 param是这个函数的参数
// 时间长度可以更改 elapsedTime
function oneSecondTimer (callback, param) {
let startTime = null
function tick (timestamp) {
if (!startTime) {
startTime = timestamp
}
const elapsedTime = timestamp - startTime
if (elapsedTime >= 1000) {
callback(param)
return
}
requestAnimationFrame(tick)
}
requestAnimationFrame(tick)
}