操作
2023年12月25日
一、实现准时的 setTimeout
setTimeout
是不准的。因为 setTimeout
是一个宏任务,它的指定时间指的是:进入主线程的时间。所以什么时候可以执行 callback
,需要看主线程前面还有多少任务待执行。
因此, 解决方案为: setTimeout
系统时间补偿。当每一次定时器执行时后,都去获取系统的时间来进行修正,虽然每次运行可能会有误差,但是通过系统时间对每次运行的修复,能够让后面每一次时间都得到一个补偿。
1.1 实现
function setAccurateTimeout(cb, delay = 0, tolerance = 10) {
let start = Date.now();
function loop() {
let delta = Date.now() - start;
let adjustedDelay = delay - delta;
if (adjustedDelay <= tolerance) {
cb();
} else {
setTimeout(loop, Math.max(0, adjustedDelay));
}
}
loop();
}
1.2 测试
console.time('timer');
setAccurateTimeout(() => {
console.timeEnd('timer');
console.log('准时的 setTimeout');
});
二、serInterval 模拟 setTimeout
function simulateSetTimeout(func, timeout) {
let timer = null;
timer = setInterval(() => {
clearInterval(timer);
func();
}, timeout);
return () => clearInterval(timer);
}
const cancel = simulateSetTimeout(() => {
console.log(1);
}, 3000);
setTimeout(() => {
cancel();
}, 3100);
三、requestAnimationFrame 模拟 setTimeout
function simulateSetTimeout(cb, delay) {
let startTime = Date.now();
loop();
function loop() {
const now = Date.now();
if (now - startTime >= delay) {
cb();
return;
}
requestAnimationFrame(loop);
}
}
simulateSetTimeout(() => {
console.log('setTimeout');
}, 1000);