用 setTimeout 实现 setInterval
使用 setTimeout 递归调用来模拟 setInterval 的效果
问题
如何使用 setTimeout 实现 setInterval 的功能?
解答
setInterval 的问题
setInterval 每隔一段时间将回调函数加入事件队列,而不是立即执行。当执行栈中的任务耗时过长时,事件队列中会积累多个定时器事件,导致这些事件在执行栈清空后连续执行,无法保证固定的时间间隔。
使用 setTimeout 模拟
通过 setTimeout 递归调用可以解决这个问题,确保上一个任务执行完成后才触发下一个定时器。
function mySetInterval(fn, timeout) {
// 控制器,用于停止定时器
var timer = {
flag: true
};
// 递归函数,模拟 setInterval
function interval() {
if (timer.flag) {
fn();
setTimeout(interval, timeout);
}
}
// 启动定时器
setTimeout(interval, timeout);
// 返回控制器,用于清除定时器
return timer;
}
// 使用示例
var timer = mySetInterval(() => {
console.log('执行任务');
}, 1000);
// 停止定时器
// timer.flag = false;
清除定时器的实现
function myClearInterval(timer) {
timer.flag = false;
}
// 使用
var timer = mySetInterval(() => {
console.log('执行任务');
}, 1000);
// 3秒后停止
setTimeout(() => {
myClearInterval(timer);
}, 3000);
关键点
setInterval会在事件队列中积累多个回调,可能导致连续执行setTimeout递归调用确保前一个任务完成后才执行下一个- 使用对象的
flag属性控制递归的继续或停止 - 每次递归都创建新的
setTimeout,避免事件堆积
目录