防抖是事件停止触发后延迟执行最后一次调用,节流是固定时间间隔内最多执行一次;二者均用于优化高频事件性能,另有时间戳+定时器组合节流、requestAnimationFrame节流及Lodash封装实现。

防抖和节流是前端开发中用于控制高频事件触发频率的两种核心策略。它们在处理如 resize、scroll、input、mousemove 等连续触发事件时,能有效避免函数被过度调用,从而提升性能与响应稳定性。以下是两种机制的原理说明与具体实现方式:
一、防抖的机制与实现
防抖的机制是:**在事件被频繁触发时,仅执行最后一次触发所对应的函数调用,中间所有触发均被忽略**。其实质是每次触发都重置计时器,只有当事件停止触发且超过设定延迟后,才真正执行函数。
1、定义一个函数,接收原函数 fn 和延迟时间 delay 作为参数。
2、在函数内部声明一个 timer 变量用于存储定时器 ID。
3、返回一个闭包函数,在其内部先清除已存在的定时器(clearTimeout(timer))。
4、再使用 setTimeout 设置新的延时任务,延迟执行 fn,将 timer 赋值为该定时器 ID。
5、若需支持立即执行模式(首次触发即执行,后续连续触发则重置),可在闭包中增加 leading 参数判断逻辑,并通过首次标记与定时器状态协同控制。
二、节流的机制与实现
节流的机制是:**限制函数在指定时间间隔内最多执行一次,无论事件触发多少次,都按固定节奏执行**。其实质是在函数执行后锁定一段时间,在锁定期内忽略新触发,锁定结束才允许下一次执行。
1、定义一个函数,接收原函数 fn 和间隔时间 delay 作为参数。
2、在函数内部声明一个变量 lastTime 记录上一次执行的时间戳(初始为 0)。
3、返回一个闭包函数,在其内部获取当前时间戳 currentTime。
4、判断 currentTime - lastTime 是否大于等于 delay,若成立,则执行 fn 并更新 lastTime = currentTime。
5、若需支持时间戳+定时器双模式(更平滑的节流效果),可额外维护一个 timer 变量,当 timer 存在时不启动新定时器,待 timer 执行完毕后再清空并允许下一轮调度。
三、基于时间戳与定时器组合的节流实现
该方式兼顾执行时机可控性与响应及时性,避免纯时间戳模式在事件停止后无法触发末次调用的问题,也规避纯定时器模式在事件持续触发时始终不执行首尾的问题。
1、定义函数,接收 fn、delay 和可选 options(含 leading、trailing 配置)。
2、初始化 timer = null、lastTime = 0。
3、在闭包中获取 currentTime,计算剩余等待时间 remaining = delay - (currentTime - lastTime)。
4、若 remaining delay(时间倒流校验),则立即执行 fn 并更新 lastTime;否则若 timer 不存在且 trailing 为 true,则设置 setTimeout 延迟执行 fn。
5、若 leading 为 false 且 timer 不存在,则在首次触发时启动定时器,确保至少有一次执行机会。
四、使用 requestAnimationFrame 的轻量节流实现
requestAnimationFrame 是浏览器专门为动画优化的 API,其回调函数会在下一次重绘前执行,天然具备约 16ms 的帧率限制特性,适合对视觉反馈要求高的场景(如 scroll、mousemove 的位置同步)。
1、定义一个函数,接收 fn 作为参数。
2、声明一个变量 isRequesting = false 用于标识当前是否已有 rAF 请求待执行。
3、返回闭包函数,在其内部若 isRequesting 为 false,则设为 true 并调用 requestAnimationFrame。
4、在 rAF 回调中执行 fn,完成后将 isRequesting 设为 false,允许下次触发进入队列。
5、该方式无需手动管理时间间隔,自动适配屏幕刷新率,且不会造成丢帧或强制同步阻塞。
五、Lodash 库中的 debounce 与 throttle 函数调用方式
Lodash 封装了健壮的防抖与节流实现,支持最大延迟、取消、刷新、pending 状态查询等扩展能力,适用于生产环境快速集成。
1、通过 npm install lodash 安装依赖,或使用 CDN 引入。
2、使用 import { debounce, throttle } from 'lodash' 导入对应函数。
3、对目标函数进行包装:const debouncedFn = debounce(handler, 300, { leading: false, maxWait: 500 })。
4、对节流函数可配置 options:const throttledFn = throttle(handler, 100, { leading: true, trailing: true })。
5、调用 debouncedFn.cancel() 可立即清除待执行的防抖任务;throttledFn.flush() 可强制执行挂起的节流回调。










