setTimeout和setInterval有什么区别呢?
setTimeout
和 setInterval
都是 JavaScript 中用于定时执行代码的函数,但它们的工作方式有所不同:
setTimeout:
- 执行一次:
setTimeout
只执行一次回调函数,在指定的延迟时间之后。 - 用法:
setTimeout(callback, delay, arg1, arg2, ...)
callback
: 要执行的函数。delay
: 延迟时间,以毫秒为单位。arg1, arg2, ...
: 传递给回调函数的参数 (可选)。
- 返回值: 返回一个唯一的 ID,可以使用
clearTimeout(id)
来取消定时器。
setInterval:
- 重复执行:
setInterval
会重复执行回调函数,每隔指定的延迟时间执行一次,直到被清除或窗口关闭。 - 用法:
setInterval(callback, delay, arg1, arg2, ...)
callback
: 要执行的函数。delay
: 每次执行之间的延迟时间,以毫秒为单位。arg1, arg2, ...
: 传递给回调函数的参数 (可选)。
- 返回值: 返回一个唯一的 ID,可以使用
clearInterval(id)
来取消定时器。
关键区别总结:
特性 | setTimeout | setInterval |
---|---|---|
执行次数 | 一次 | 重复执行 |
取消方法 | clearTimeout() |
clearInterval() |
延迟的精确性 | 更精确 | 可能会累积误差 |
关于 setInterval
的累积误差:
由于 JavaScript 是单线程的,如果回调函数的执行时间超过了 setInterval
设置的延迟时间,下一次执行就会被推迟,导致累积误差。 例如,如果 setInterval
设置为每 100ms 执行一次,但回调函数需要 150ms 才能完成,那么实际的间隔时间就会大于 100ms。 长期运行下来,这种误差会越来越大。
选择哪个函数:
- 如果只需要在一段时间后执行一次代码,使用
setTimeout
。 - 如果需要重复执行代码,使用
setInterval
,但要注意潜在的累积误差问题。 如果对时间的精确性要求较高,可以考虑使用递归的setTimeout
来模拟setInterval
,并在每次执行后重新计算下一次执行的时间。
递归 setTimeout
模拟 setInterval
的例子:
function mySetInterval(callback, delay, ...args) {
let timerId;
function run() {
callback(...args);
timerId = setTimeout(run, delay);
}
timerId = setTimeout(run, delay);
return timerId; // 可以使用 clearTimeout 清除
}
// 使用示例:
let counter = 0;
const intervalId = mySetInterval(() => {
console.log(`Counter: ${counter++}`);
if (counter > 5) {
clearTimeout(intervalId);
}
}, 1000); // 每秒打印一次,最多打印6次
这个例子中,每次 callback
执行完后,都会使用 setTimeout
重新安排下一次执行,从而避免了 setInterval
的累积误差问题。 并且也返回了 ID,可以方便地使用 clearTimeout
清除。