防抖和节流均通过“记状态+控时机”限制函数执行频率,依赖闭包保存timer/ispending/lasttime等状态,以及定时器或时间戳判断执行时机;防抖适用于等待操作稳定后执行(如搜索、提交),节流适用于高频持续反馈场景(如滚动、拖拽)。

直接说核心:防抖和节流都是靠“记状态 + 控时机”来压住函数调用频率,背后离不开闭包和定时器(或时间戳)这两样东西。
防抖就像电梯关门
你按电梯按钮,它不会马上关门——而是开始倒计时(比如 500ms)。如果倒计时没走完又有人进来,就清掉旧倒计时、重新开始。只有连续 500ms 没人按,门才关、电梯才走。
对应到代码里:
- 用一个变量(比如 timer)记住当前有没有挂起的定时器
- 每次触发事件,先 clearTimeout(timer) 把上一次计划取消
- 再 setTimeout 新建一个,等 delay 时间后才真正执行函数
- 这个 timer 能一直存在,靠的是闭包——外层函数执行完了,内层函数还在引用它,所以不会被回收
节流就像公交发车
公交车每 10 分钟一班,不管站台上挤多少人、来了几次,到了点就发车,不等人也不多发。
实现方式有两种常见思路:
- 定时器版:设个开关(比如 isPending = true),触发时发现开着,就啥也不干;等定时器执行完函数,再把开关关上(isPending = false),下一次才能进
- 时间戳版:记下上次执行的时间(lastTime),每次触发时算一下“现在 - lastTime”是否 ≥ delay,够了就执行并更新 lastTime,不够就跳过
它们都依赖闭包“存住状态”
不管是 timer、isPending 还是 lastTime,这些变量都定义在外层函数里,返回的事件处理函数能一直访问它们——没有闭包,每次触发都是“全新开始”,根本控不住节奏。
而定时器(setTimeout)或时间差计算(Date.now()),就是那个决定“能不能执行”的裁判。
一句话分清什么时候用哪个
用户操作要“等稳了再干”——选防抖(如输入搜索、防重复提交);
用户操作要“持续反馈但不能太密”——选节流(如滚动监听、鼠标移动、窗口缩放)。











