文章目录
- [防抖 (Debounce) 与 节流 (Throttle)](#防抖 (Debounce) 与 节流 (Throttle))
-
- [一、 核心定义与区别](#一、 核心定义与区别)
-
- [1. 防抖 (Debounce)](#1. 防抖 (Debounce))
- [2. 节流 (Throttle)](#2. 节流 (Throttle))
- [3. 对比总结](#3. 对比总结)
- [二、 使用场景](#二、 使用场景)
-
- [🛠 防抖 (Debounce) 的使用场景](#🛠 防抖 (Debounce) 的使用场景)
- [⚙️ 节流 (Throttle) 的使用场景](#⚙️ 节流 (Throttle) 的使用场景)
- [三、 使用它们的好处](#三、 使用它们的好处)
- [四、 常见面试题](#四、 常见面试题)
-
- [A. 手写实现一个基础版防抖](#A. 手写实现一个基础版防抖)
- [B. 手写实现一个基础版节流(定时器版)](#B. 手写实现一个基础版节流(定时器版))
防抖 (Debounce) 与 节流 (Throttle)
在前端开发中,防抖 和节流是优化高频率执行代码(如滚动、输入、调整窗口大小)的核心手段。
一、 核心定义与区别
1. 防抖 (Debounce)
- 定义 :在事件被触发 n n n 秒后再执行回调,如果在这 n n n 秒内事件又被触发,则重新计时。
- 形象比喻:就像电脑的**"待机睡眠"**。你最后一次操作鼠标后,电脑开始倒计时 10 分钟;如果你在第 9 分钟动了一下,倒计时立刻重置,重新等 10 分钟。
2. 节流 (Throttle)
- 定义 :规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发了多次函数,只有一次生效。
- 形象比喻 :就像**"红绿灯"或"水龙头滴水"**。无论路口有多少辆车想冲过去,绿灯亮起的时间间隔是固定的;或者水龙头每隔 3 秒滴一滴水,中间你如何拧开关都没用。
3. 对比总结
| 特性 | 防抖 (Debounce) | 节流 (Throttle) |
|---|---|---|
| 核心逻辑 | 重置计时器,只执行最后一次 | 锁定执行周期,每隔一段时间执行一次 |
| 关注点 | 关注"空闲时间",等到彻底安静后再执行 | 关注"执行频率",在持续触发中按节奏执行 |
| 执行次数 | 无论触发多少次,最终可能只执行一次 | 持续触发时,会按固定频率执行多次 |
二、 使用场景
🛠 防抖 (Debounce) 的使用场景
- 搜索框输入 (Input):用户不停输入字符时,没必要每打一个字就发一次 AJAX 请求,等用户停下 500ms 后再发送。
- 窗口大小调整 (Resize):用户拉伸窗口时,等拉伸结束再重新计算布局或 ECharts 图表自适应。
- 表单提交按钮:防止用户因为手抖或网络延迟快速多次点击,导致重复提交订单或数据。
⚙️ 节流 (Throttle) 的使用场景
- 鼠标移动 (Mousemove):在实现拖拽效果时,每秒计算几十次位置足够了,不需要每微秒都计算。
- 滚动监听 (Scroll):监听用户滚动到底部加载更多(Infinite Scroll),每 200ms 检查一次距离即可。
- 游戏技能释放:无论玩家按键多快,技能的冷却时间(CD)是固定的,强制限制触发频率。
三、 使用它们的好处
- 性能优化:减少 CPU 和内存的占用,避免高频操作导致页面卡顿、掉帧。
- 节省资源:显著减少向后端发送 API 请求的次数,减轻服务器压力和带宽消耗。
- 提升用户体验:避免因为无效的重复计算或异步请求冲突导致页面响应混乱。
四、 常见面试题
A. 手写实现一个基础版防抖
javascript
function debounce(fn, delay) {
let timer = null;
return function(...args) {
if (timer) clearTimeout(timer); // 只要进来就清空之前的计时
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
B. 手写实现一个基础版节流(定时器版)
javascript
function throttle(fn, delay) {
let timer = null;
return function(...args) {
if (!timer) { // 如果没锁,就设置一个定时器
timer = setTimeout(() => {
fn.apply(this, args);
timer = null; // 执行完后解锁
}, delay);
}
};
}