怎样解决setTimeout执行时间不准确的问题?
1、while循环;可以使用while循环来轮询检测是否达到执行的时间间隔,如果达到则执行回调,
缺点:JS是单线程执行的,此时强行将线程用于setTimeout回调函数的执行判断,会使页面进入卡死状态,不可取!
优点:误差为0
2、web worker+while循环;将while循环放到web worker线程中执行,减轻主线程的负担;
缺点:worker线程内还是会被while循环占用,无法接收到更多信息;多个定时器无法同时执行,需要开启多个worker线程;
优点:误差小
// worker.js文件:
// worker生成器
const createWorker = (fn, options) => {
const blob = new Blob(['(' + fn.toString() + ')()']);
const url = URL.createObjectURL(blob);
if (options) {
return new Worker(url, options);
}
return new Worker(url);
}
// 创建worker 部分
const worker = createWorker(function () {
var count = 1
onmessage = function (e) {
const date = Date.now();
while (true) {
// 拿到当前每一刻的时间和wait时间比对,如果到达wait时间,则发出信号
const now = Date.now();
if (now - date >= e.data) {
// 限制最多执行20次
postMessage(count >= 20 ? 0 : 1);
count++
return;
}
}
}
})
let isStart = false;
const speed = 500
// 每隔半毫秒打印1
function cb () {
console.log(1);
}
function timer () {
worker.onmessage = function (e) {
cb()
isStart = e.data === 1
if (isStart) {
worker.postMessage(speed);
}
}
worker.postMessage(speed);
}
timer()
3、使用系统时间补偿;当每一次定时器执行后, 都会去获取系统时间进行修正;
优点:主线程不阻塞,也没创建其他worker线程;执行误差小
综上:此方案最优
function timer() {
var speed = 500
counter = 1
start = new Date().getTime()
var timer = ''
function instance() {
var ideal = counter * speed
real = new Date().getTime() - start
counter++
var diff = real-ideal
console.log(`实际时间real: ${real}, 理想时间ideal: ${ideal}, 差值diff: ${diff}`);
if(counter === 20) {
clearInterval(timer)
return
}
// 通过系统时间进行修复,每次wait的时间是动态变化的,这个wait时间通过计算得到
timre = window.setTimeout(function(){
instance()
}, speed - diff)
}
window.setTimeout(function() {
instance()
}, speed)
}
timer()
参考博客:如何实现准时的 setTimeout?