概述
setTimeout
和 setInterval
是 JavaScript 中常用的定时器。
-
setTimeout
-> 定时器到期后执行一个函数或指定的一段代码 -
setInterval
-> 重复调用一个函数或执行一个代码段,在每次调用之间具有固定的时间延迟
setTimeout
模拟 setInterval
setTimeout 模拟 setInterval demo
let count = 0;
let timerId = null;
timerId = setTimeout(function run() {
console.log("run -> ", count);
if (count >= 3) {
clearTimeout(timerId);
return;
}
count += 1;
timerId = setTimeout(run, 1000);
}, 1000);
可以看到控制台的 count
一直在增长。同样的使用 setInterval
也可以实现上述效果
let count = 0;
let timerId = null;
timerId = setInterval(function run() {
console.log("run -> ", count);
if (count >= 3) {
clearInterval(timerId);
return;
}
count += 1;
}, 1000);
为什么使用 setTimeout 模拟 setInterval
setInterval
缺点:
- 某些间隔会被跳过(丢帧现象)
- 定时器之间的间隔会比预期小
让我们更新一下我们 setInterval
的 demo
let count = 0;
let doSomeThing = () => {
// 这里会进行很多计算量很大的操作,将会耗时 1.6s
};
let run = () => {
console.log("run -> ", count);
count += 1;
doSomeThing();
};
let timerId = setInterval(run, 1000);
之后我们逐步分析一下接下来的5秒会发生什么事情,我们假设 setInterval
在 0s 时触发
-
0 - 1s
- 0s 时
setInterval
触发
- 0s 时
-
1s - 2s
- 1s 时
run
(此处的run
我们取名run1
)被加入队列并执行
- 1s 时
-
2s - 3s
- 2s 时
run
(此处的run
我们取名run2
)被加入队列,但是此时run1
别没有执行结束,所以run2
不能立即执行。 - 2.6s 时
run1
执行结束,run2
开始执行
- 2s 时
-
3s - 4s
- 3s 时
run
(此处的run
我们取名run3
)被加入队列,但是此时run2
别没有执行结束,所以run3
不能立即执行。
- 3s 时
-
4s - 5s
-
4s 时
run
(此处的run
我们取名run4
)应该被加入队列,但是由于目前队列中有run3
,所以run4
被忽略注意:当使用
setInterval()
时,仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中。run3
是该定时器的代码实例,所以run4
不会被加入到队列中,从而导致丢帧现象 4.2s 时
run2
执行结束,run3
开始执行
-
使用 setTimeout
let count = 0;
let doSomeThing = () => {
// 这里会进行很多计算量很大的操作,将会耗时 1.6s
};
let timer = null;
let run = () => {
console.log("run -> ", count);
count += 1;
doSomeThing();
timer = setTimeout(run, 1000);
};
timerId = setTimeout(run, 1000);
同样的,我们也来分析一下接下来的5秒会发生什么,我们假设 setTimeout
在 0s 时触发
-
0 - 1s
- 0s 时
setTimeout
触发
- 0s 时
-
1s - 2s
- 1s 时
run
(此处的run
我们取名run1
)被加入队列并执行
- 1s 时
-
2s - 3s
- 2.6s 时
run1
执行结束
- 2.6s 时
-
3s - 4s
- 3.6s 时
run
(此处的run
我们取名run2
)被加入队列并执行
- 3.6s 时
4s - 5s
-
5s - 6s
- 5.2s 时
run2
执行结束
- 5.2s 时
总结
由于 setInterval
有如下缺点
- 某些间隔会被跳过(丢帧现象)
- 定时器之间的间隔会比预期小
所以使用 setTimeout
代替 setInterval
吧!