跳到主要内容

操作

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);