怎样解决setTimeout执行时间不准确的问题?
怎样解决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 === 1if (isStart) {worker.postMessage(speed);}}worker.postMessage(speed);
}timer()
3、使用系统时间补偿;当每一次定时器执行后, 都会去获取系统时间进行修正;
优点:主线程不阻塞,也没创建其他worker线程;执行误差小
综上:此方案最优
function timer() {var speed = 500counter = 1start = new Date().getTime()var timer = ''function instance() {var ideal = counter * speedreal = new Date().getTime() - startcounter++var diff = real-idealconsole.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?
使用 Web Workers - Web API 接口参考 | MDN