setInterval机制:
- 延时一段时间后,将任务push到任务队列中排队执行;
- 在每次把任务 push 到任务队列前,都要进行一下判断(看上次的任务是否仍在队列中,如果有则不添加,没有则添加)。
会导致的问题
- 前一任务结束到当前任务开始的时间间隔与设置的delay值不符。
- 可能出现某些任务被跳过的情况
(1)任务添加的时间间隔误差较大的情况
setInterval(foo, delay)
//当foo执行消耗800ms,delay为1000ms时,前一个任务执行结束到后一个任务开始执行只间隔了200ms
(2) 某些间隔会被跳过。 setInterval 每隔 100ms 往队列中添加一个事件;100ms 后,添加 T1 定时器代码至队列中,主线程中还有任务在执行,所以等待。开始执行 T1 定时器代码;又过了 100ms,T2 定时器被添加到队列中,主线程还在执行 T1 代码,所以等待;又过了 100ms,理论上又要往队列里推一个定时器代码,但由于此时 T2 还在队列中,所以 T3 不会被添加(T3 被跳过),结果就是此时被跳过;T1 定时器执行结束后会马上执行了 T2 代码,所以并没有达到定时器的效果。
解决方案
使用setTimeout 模拟 setInterval。
setTimeout 机制:产生的任务会直接 push 到任务队列中。
function mySetInterval(fun, delay) {
let timer = null
function interval() {
//fun中的同步代码执行完之后,再开始定时
fun()
setTimeout(interval, delay);
}
interval()
return {
cancel: () => {
clearTimeout(timer)
}
}
}
mySetInterval(() => console.log('mySetInterval'), 1000)