setTimeout执行单次延迟任务,到点执行一次后自动销毁;setInterval启动周期性调度器,不手动清除会持续触发回调,易因回调超时导致任务堆积、节奏失控,推荐用递归setTimeout替代。
根本区别不在语法,而在执行模型:setTimeout 注册一个**单次延迟任务**,到点执行一次,自动销毁;setInterval 启动一个**周期性调度器**,只要不手动停,它就会按间隔不断尝试触发回调。
setTimeout(fn, 1000),意思是“1 秒后调用 fn 一次”,之后再无后续setInterval(fn, 1000),意思是“从现在起,每 1 秒调用一次 fn”,直到你调用 clearInterval(id) 或页面卸载clearTimeout(id) / clearInterval(id) —— 混用会失效因为 setInterval 不管上一次回调有没有执行完。如果回调耗时超过设定间隔(比如 setInterval(fn, 100),但 fn 平均要跑 150ms),浏览器会把后续回调“堆积”进任务队列,等前一个结束立刻执行下一个,造成密集连发、时间漂移甚至卡顿。
setTimeout:function tick() {
doWork();
setTimeout(tick, 1000); // 下次执行由本次回调主动发起
}
tick();现代写法统一推荐传函数引用 + 后续参数,避免用字符串形式(如 "fn()")—— 它会触发 eval,有安全风险、性能差、调试难,且无法正确捕获闭包变量。
setTimeout(greet, 1000, 'Alice', 28)
setTimeout(() => greet('Alice'), 1000)
setTimeout("greet('Alice')", 1000)
setInterval 同样支持函数引用+参数,但别忘了清除逻辑必须在作用域内保留 ID 引用定时器没被清除,它的回调函数和所有闭包引用的对象就一直活在内存里。尤其在单页应用中,组件卸载了但 setInterval 还在跑,轻则重复请求、重则崩溃。
useEffect 里启用了 setInterval,却没在 cleanup 函数里调用 clearInterval
console.warn("interval still running!") 防遗漏setInterval 也会持续占用资源,直到进程终止setTimeout,而不是无脑选 setInterval。那个看似省事的“自动循环”,往往藏着最隐蔽的时序陷阱。