时钟准确的定时轮询函数
js的单线程异步机制决定了setInterval和setTimeout函数的时钟不准确性
浏览器原生的setTimeout(fn,timeout)函数的原理,是保证timeout时间后,将回调函数fn加入event loop的消息队列,不是保证timeout时间后一定执行。
回调函数加入的消息队列后,实际的执行时间要等到 调用栈中已有函数 + 消息队列已有消息执行完毕。
所以回调函数的实际执行时间与设定的timeout有偏差。
setInterval函数也同样有偏差。
以下实现了一个时间准确的定时轮询函数。
setClockInterval 函数
/**
* setClockInterval是时钟准确的定时轮询函数(原生setInterval时钟不准确)
* @param func 与原生setInterval参数一致
* @param interval 与原生setInterval参数一致
* @return timer 类型为number
*/
const timerMap = new Map()
export function setClockInterval(func: Function, interval: number) {
let start: number
let tick: number
let clockTimer: number | null
const timerId = Math.floor(Math.random() * 1e10)
const recurFunc = () => {
func()
const realExcuTime = new Date().getTime()
if (!start) {
start = realExcuTime
}
tick = tick || start
// bias是本次实际执行时间戳 与 理论执行时间戳tick之间的偏差
// bias一定>=0,因为浏览器的setTimeout setInterval只会准时或者延迟执行,不会提前执行
// 经过本地浏览器统计 bias平均值在10ms以内,最大值在20ms左右
const bias = realExcuTime - tick
console.log(`实际执行时间戳${realExcuTime},理论计划执行时间戳${tick},本次偏差${bias}ms`);
// 下次tick时间戳
tick += interval
// 因为本次实际执行时间有bias的延迟,所以下次执行提前
clockTimer = window.setTimeout(recurFunc, interval - bias)
timerMap.set(timerId, clockTimer)
}
recurFunc()
return timerId
}
clearClockInterval 函数
/**
* clearClockInterval 用于终止 setClockInterval 的定时轮询
* @param timer 是 setClockInterval 的返回值
*/
export function clearClockInterval(timerId: number) {
if (timerMap.has(timerId)) {
window.clearTimeout(timerMap.get(timerId))
} else {
console.warn(`timerId${timerId}not found`);
}
}
demo执行效果
bias平均值在10ms以内,最大值在20ms左右
09:45:39.557 util.ts:23 实际执行时间戳1690508739557,理论计划执行时间戳1690508739550,本次偏差7ms
09:45:40.555 util.ts:23 实际执行时间戳1690508740555,理论计划执行时间戳1690508740550,本次偏差5ms
09:45:41.561 util.ts:23 实际执行时间戳1690508741561,理论计划执行时间戳1690508741550,本次偏差11ms
09:45:42.559 util.ts:23 实际执行时间戳1690508742559,理论计划执行时间戳1690508742550,本次偏差9ms
09:45:43.559 util.ts:23 实际执行时间戳1690508743559,理论计划执行时间戳1690508743550,本次偏差9ms
09:45:44.560 util.ts:23 实际执行时间戳1690508744560,理论计划执行时间戳1690508744550,本次偏差10ms
09:45:45.556 util.ts:23 实际执行时间戳1690508745555,理论计划执行时间戳1690508745550,本次偏差5ms
09:45:46.552 util.ts:23 实际执行时间戳1690508746552,理论计划执行时间戳1690508746550,本次偏差2ms
09:45:47.562 util.ts:23 实际执行时间戳1690508747562,理论计划执行时间戳1690508747550,本次偏差12ms
09:45:48.561 util.ts:23 实际执行时间戳1690508748561,理论计划执行时间戳1690508748550,本次偏差11ms
上次更新: