防抖与节流
- 文章發表於
前言
想象一下,当你在某个网站通过搜索框寻找东西时,你输入的每一个字都会立即触发一次自动推荐(auto suggest)的 API,这样的使用体验可能会让用户直接离开,转向竞品。
虽然功能看似简单,但如果没有妥善处理,可能会造成一连串的问题:
- 服务器过载:过于频繁的 API 请求会对服务器造成巨大的负担。如果后端没有做流量管控,甚至可能导致服务器崩溃。
- 竞态条件(Race Condition):例如,你先输入「apple is」,接着立刻改成「banana」,由于请求响应的时间差,画面上可能同时有机会出现「apple is」或「banana」的推荐结果。
- 界面卡顿:当每输入一个字就立即更新结果,画面会不停地在「加载中」与「显示结果」之间闪烁切换,造成突兀且不舒服的使用体验。
这篇文章将会介绍两种常见的解决方案,来解决类似的问题:防抖(Debounce)和节流(Throttle)。
节流
什么是节流?
节流是一种让函数执行「平均分布在时间轴上」的技巧,无论触发事件的频率有多高,节流确保函数在指定的间隔内最多被调用一次,例如设定每秒执行一次,那即使事件连续被触发 100 次,也只会每秒处理一次,节奏是固定的。
核心原理
- 第一次函数调用时立即执行
- 设定一个冷却期(cooling period)
- 在冷却期内,忽略或记录新的函数调用
- (选用) 冷却期结束后,可以再次执行上一个函数
使用场景
节流适合用在「需要稳定执行频率」的情境,例如:
- 滚动事件:限制滚动事件处理频率
- 窗口调整大小:限制调整大小时的重新计算
- 鼠标移动:限制鼠标移动事件处理频率
- 游戏控制:限制按键事件处理频率
- 拖拽和绘图操作:确保平滑的视觉效果
Throttle 的实现
这个基本实现在大多数简单场景中已经足够,比如限制按钮点击或基本的滚动事件处理。
function throttle(func, wait) {let shouldThrottle = false;return function (...args) {if (shouldThrottle) return;shouldThrottle = true;func.apply(this, args);setTimeout(() => {shouldThrottle = false;}, wait);};}
防抖
什么是防抖?
防抖是另一种控制函数执行频率的技术,它保证函数在指定时间「最后一次」触发后才执行一次。简单来说,只有在一段时间内没有新的触发时,才真正执行函数;节流则是让函数以固定频率执行,即使中间有很多触发,也只会定期处理一次。
核心原理
- 第一次触发时,设定一个冷却期(cooling period)
- 在冷却期内,若有新的触发,就取消上一次的计时器并重置冷却期
- 冷却期结束后,执行函数,并且清除计时器
使用场景
防抖特别适合用在「等待用户停下来再做事」的情境,换句话说就是,它最适合应对那种短时间内会被大量触发的事件,但我们其实只在意「最后一次」的状况。
- 搜索建议:用户暂停输入后才发起搜索请求。
- 表单验证:输入框停止输入后才触发验证。
- 自动保存:用户停止编辑一段时间后才自动保存。
防抖的实现
function debounce(func, wait) {let timeId = null;return function (...args) {if (timeId) {clearTimeout(timeId);}timeId = setTimeout(() => {func.apply(this, args);}, wait);};}
节流 & 防抖比较
如果您喜欢这篇文章,请点击下方按钮分享给更多人,这将是对笔者创作的最大支持和鼓励。