← 返回目录

14. 定时器叠加与内存泄漏专项

定时器的坑:叠加执行、内存泄漏、this 丢失。

核心三个坑:
叠加——上一次还没执行完下一次又来了
内存泄漏——组件销毁了定时器还在跑
this 丢失——回调里 this 不是原来的对象

坑:切换页面要 clearInterval、用闭包或 bind 修 this、防抖节流解决叠加

14.1 互动演示(错误版 vs 修复版 对比)

错误版(叠加): 修复版(先清再设):
错误版(叠加)
0
在跑定时器:0 个
修复版(先清再设)
0
在跑定时器:1 个
左按钮连点 5 次看数字疯跳;右按钮连点 5 次看速度恒定。

14.2 知识点讲解

① 定时器叠加(重复创建)

点一次按钮创建一个定时器本来没问题,但每次都不清旧的、又开新的,多个定时器同时跑 → 回调被反复执行 → 数字跳得越来越快、逻辑错乱。

// 错误示范:点一下就新开一个,从不关旧的
btn.onclick = function () {
  setInterval(function () {
    // 每点一次就多一个在跑
    console.log("叠加 bug");
  }, 1000);
};

// 连点 5 下 = 5 个定时器同时干活!数字疯跳

// 正确做法:开新的之前,先把旧的关掉
// 用变量把定时器编号记下来
let loopTimer = null;
btn.onclick = function () {
  if (loopTimer) {
    // 手上已经有一个了
    // 先把旧的辞退
    clearInterval(loopTimer);
  }
  loopTimer = setInterval(function () {
    // 再招新的
    console.log("正常循环");
  }, 1000);
};

// 任何时候手上只留一个定时器,不会叠加

双重拦截最稳:① timer 变量判断(if(timer) return)+ ② 按钮 disabled——抽奖、抢购、搜索防抖都这么干(第 16 页实战会用到)。

② 内存泄漏:定时器为什么"偷内存"?

// 为啥会"偷内存":
// 原因 1:页面切走了、弹窗关了、组件拆了,可你没清定时器
// → 它还在后台默默跑,白白占着内存
// 原因 2:定时器里还拽着页面上的 DOM、变量不放
// → 页面都没了,JS 引擎以为"还有人在用",不敢回收
// 怎么修:在关弹窗、关页面的时候,把定时器都清掉
closeBtn.addEventListener("click", function () {
  // 清循环闹钟
  clearInterval(loopTimer);
  // 清单次闹钟
  clearTimeout(delayTimer);
});

开发硬性规范:凡是循环定时器,必须配套清除逻辑;页面销毁、重复触发场景务必手动清空定时器 ID。

③ 怎么自查?(作业练习四的思路)

// 1. 按 F12 打开 Console,盯着看有没有"停不下来的输出"
// 2. 把弹窗关了,等 2 秒再看 Console 是不是还在打印
// → 还在打 = 定时器没关干净,漏了
// 3. 在关闭事件里加了 clearInterval 之后输出停了 = 修好了
一句话记住:开新定时器前先 clearInterval 旧的(防叠加);弹窗关闭/页面卸载时清掉所有定时器(防泄漏)

本页重点

API作用参数返回值代码示例
setInterval(函数, 毫秒)重复点会叠加,越跑越快函数、毫秒IDlet t = setInterval(fn, 100); // 重复点会叠加
clearTimeout(delayTimer)清单次闹钟(关弹窗/页面时一起清)定时器 IDclearTimeout(delayTimer); // 关弹窗时清
clearInterval(旧ID)重定前先把旧闹钟清掉定时器 IDclearInterval(oldId); // 重定前先清旧的
按钮.disabled = true跑起来就锁按钮,防连点true / falsebtn.disabled = true; // 锁按钮防连点