2020-11-05 11:36:14
setTimeout 和 setInterval 的核心区别在于执行次数和内存管理机制。setTimeout 仅执行一次回调,而 setInterval 会重复执行直至被清除。以下是详细分析:
一、功能差异setTimeout
单次执行:在指定延迟后触发一次回调函数。
链式调用模拟循环:可通过在回调中递归调用 setTimeout 实现类似循环效果(如 setTimeout(fn, delay) → fn() 内再调用 setTimeout)。
示例:
setTimeout(() => console.log("执行一次"), 1000);setInterval
重复执行:按固定间隔重复触发回调,直到调用 clearInterval。
固定间隔:间隔时间包含回调执行时间,可能导致实际间隔不精确(若回调耗时超过间隔)。
示例:
const intervalId = setInterval(() => console.log("重复执行"), 1000);// 需手动清除:clearInterval(intervalId);setTimeout 的内存优势
单次任务队列:回调仅进入事件队列一次,执行后立即释放内存。
无累积风险:即使回调耗时较长,也不会导致任务堆积(因不重复调度)。
递归调用的优化:链式 setTimeout 可动态调整下次执行的延迟时间,避免固定间隔的潜在问题。
setInterval 的内存风险
持续任务队列:即使前一次回调未完成,仍会按固定间隔添加新任务到队列。
内存泄漏场景:
回调阻塞:若回调执行时间超过间隔,任务会不断堆积(如 setInterval(fn, 100ms) 但 fn() 耗时 200ms)。
未清除定时器:页面卸载时未调用 clearInterval,导致定时器及闭包变量残留。
示例风险:
// 错误示例:回调堆积setInterval(() => { heavyTask(); // 耗时操作}, 100); // 若 heavyTask() 执行时间 >100ms,队列会无限增长推荐使用链式 setTimeout 替代 setInterval
动态间隔:可根据前次执行结果调整下次延迟(如重试机制)。
避免堆积:确保前次回调完成后再调度下一次执行。
代码示例:
function safeInterval(fn, delay) { let isActive = true; (function execute() { if (!isActive) return; fn(); setTimeout(execute, delay); })(); return () => { isActive = false; }; // 返回清除函数}const stop = safeInterval(() => console.log("安全执行"), 1000);// stop(); // 调用以终止清除定时器的必要性
组件卸载时:在 React/Vue 等框架中,需在 useEffect 或 beforeDestroy 钩子中清除定时器。
条件终止:通过标志变量控制循环执行(如上述 isActive)。
