文章中英模式
常见的前端面试题目 - 用户交互优化 - Throttle 与 Debounce
深入理解 JavaScript 中的 Throttle 节流与 Debounce 防抖技术,包含两者差异、实现原理、适用场景详解与实际范例,掌握前端性能优化与面试常考题目。
文章中英模式

懒得看文章?那就来看视频吧
什么是 Throttle 与 Debounce?为什么需要它们?
Throttle(节流)和 Debounce(防抖)是两种常用的前端性能优化技术,用于控制高频事件(如滚动、搜索、调整窗口大小)的执行频率。
- •Throttle(节流):限制函数在一段时间内只执行一次,无论触发多少次。像是「每隔 N 毫秒最多执行一次」。
- •Debounce(防抖):将多次连续触发合并为一次,只在最后一次触发后等待一段时间才执行。像是「等待 N 毫秒没有新触发才执行」。
这两种技术对于优化前端性能、提升用户体验非常重要:
- •减少不必要的函数调用
- •降低 API 请求频率
- •优化资源密集型计算
- •减少 DOM 操作频率
Throttle(节流)实现与原理
节流的核心概念是「保证在指定时间内,函数最多只能执行一次」:
function throttle(func, delay) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= delay) {
func.apply(this, args);
lastCall = now;
}
};
}
// 使用范例
const throttledScroll = throttle(() => {
console.log('滚动位置:', window.scrollY);
}, 300);
window.addEventListener('scroll', throttledScroll);图解 Throttle 执行原理:
触发事件:↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
执行函数:↓ ↓ ↓
时间轴: |--------|--------|------->
300ms 300ms 300msDebounce(防抖)实现与原理
防抖的核心概念是「等待指定时间内没有新的调用再执行函数」:
function debounce(func, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// 使用范例
const searchInput = document.getElementById('search');
const debouncedSearch = debounce((e) => {
console.log('搜索关键字:', e.target.value);
// fetchResults(e.target.value);
}, 500);
searchInput.addEventListener('input', debouncedSearch);图解 Debounce 执行原理:
触发事件:↓ ↓ ↓ ↓ ↓ ↓
重置计时:⟳ ⟳ ⟳ ⟳ ⟳ ⟳
执行函数: ✓ ✓
时间轴: |-----|-----|-----|-----|---->
等待中 等待中 执行 等待中 执行使用场景比较
Throttle 与 Debounce 适用场景比较:
| 技术 | 适用场景 | 实际应用 |
|---|---|---|
| Throttle(节流) | 滚动事件处理 | 社交媒体的无限滚动加载,每300ms检查一次滚动位置 |
| 游戏中的按键控制 | 射击游戏中限制玩家每秒最多发射5颗子弹 | |
| 地图拖动/缩放 | Google地图拖动时,每100ms才重新请求地图数据 | |
| Canvas 绘图 | 绘图应用中,笔刷跟随鼠标以固定间隔绘制点 | |
| Debounce(防抖) | 搜索框输入 | Google搜索框停止输入500ms后才发送搜索请求 |
| 表单验证 | 注册表单中,用户输入完邮箱后才检查是否已被使用 | |
| 自动保存 | Google文档在用户停止输入2秒后自动保存内容 | |
| 窗口大小调整 | 响应式网站在用户完成调整窗口大小后才重新排版 |
实际应用案例与效能差异
案例 1:滚动事件优化(使用 Throttle)
未优化前,滚动时可能会触发上百次函数调用:
// 未优化 - 每次滚动都会执行
window.addEventListener('scroll', () => {
loadMoreContent();
});
// 优化后 - 每 200ms 最多执行一次
window.addEventListener('scroll', throttle(() => {
loadMoreContent();
}, 200));案例 2:自动保存表单(使用 Debounce)
未优化前,输入每个字都会触发保存:
// 未优化 - 每次输入都会保存
editor.addEventListener('input', saveContent);
// 优化后 - 停止输入 500ms 后才保存
editor.addEventListener('input', debounce(saveContent, 500));🔥 常见面试题目
(一)Throttle 和 Debounce 的主要区别是什么?
解答:Throttle(节流)控制函数在一段时间内最多执行一次,无论触发多少次,适合持续性事件如滚动。例如:在电商网站上,当用户滚动页面时,使用 Throttle 每 200ms 检查一次是否需要加载更多商品,而不是每次滚动都触发。Debounce(防抖)则是将多次连续触发合并为一次,只在最后一次触发后等待一段时间才执行,适合连续触发但只需最终结果的场景如搜索。例如:在搜索框中,用户快速输入「React 教学」时,使用 Debounce 等待用户停止输入 500ms 后才发送 API 请求,而不是每打一个字就发送一次请求。
(二)以下代码的执行结果是什么?
let count = 0;
const btn = document.getElementById('btn');
const throttledClick = throttle(() => {
console.log(`點擊次數: ${++count}`);
}, 1000);
// 假設使用者在 2 秒內快速點擊 5 次
btn.addEventListener('click', throttledClick);解答:假设用户在 2 秒内点击 5 次,console 会输出:
- 第 0 秒时:「点击次数: 1」(首次立即执行)
- 第 1 秒时:「点击次数: 2」(间隔满 1 秒后执行)
- 第 2 秒时:「点击次数: 3」(间隔满 1 秒后执行)
(三)以下 debounce 代码的执行结果是什么?
let count = 0;
const searchInput = document.getElementById('search');
const debouncedSearch = debounce(() => {
console.log(`搜尋次數: ${++count}`);
}, 500);
// 假設使用者在 1 秒內快速輸入 5 個字元
searchInput.addEventListener('input', debouncedSearch);解答:假设用户在 1 秒内快速输入 5 个字符,console 会输出:
- 第 1.5 秒时:「搜索次数: 1」(最后一次输入后 500ms 执行)
(四)实现一个简单的搜索框 Debounce
解答:以下是一个简单的搜索框 Debounce 实现:
// HTML: <input id="search" type="text" placeholder="搜索...">
// HTML: <div id="results"></div>
function debounce(func, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => func(...args), delay);
};
}
const searchInput = document.getElementById('search');
const resultsDiv = document.getElementById('results');
const handleSearch = debounce((event) => {
const query = event.target.value;
resultsDiv.textContent = `搜索中: ${query}`;
// 实际应用中这里会发送 API 请求
}, 300);
searchInput.addEventListener('input', handleSearch);