为什么使用防抖
在前端开发中,函数防抖(debounce)是处理高频事件触发的关键手段。它的核心逻辑是在连续触发的事件停止后,仅执行最后一次调用。如果不加限制,比如在 input 输入或 window.resize 事件中直接执行逻辑,页面很容易因短时间内大量请求或计算而卡顿。
通过防抖,我们可以让函数在用户停止操作后的特定延迟内才执行,这能极大提升资源利用效率并优化用户体验。
函数防抖的应用场景
- 输入框实时搜索
用户输入关键词时若每次
keyup都发请求,接口压力会剧增。加上防抖后,只在用户停止输入(如 300ms)后才发送请求。 - 按钮防连点 提交表单或支付按钮容易因误触导致多次提交。绑定防抖函数可确保短时间内只执行一次操作。
- 窗口大小调整(resize) 布局重绘频繁触发,添加防抖能减少不必要的计算和渲染次数。
- 滚动监听 结合无限滚动或懒加载时,控制数据加载频率,避免重复请求。
原理与手写实现
原理
防抖依赖内部维护的定时器 ID。每次调用时先清除旧定时器,再启动新定时器;只有最后一次调用后的延迟时间到达,目标函数才会真正执行。
手写实现
/**
* 简易版防抖函数
* @param {Function} func - 需要防抖的函数
* @param {number} wait - 延迟时间(毫秒)
* @returns {Function} - 防抖后返回的新函数
*/
function debounce(func, wait) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, wait);
};
}
这段代码利用闭包维护独立的 timeoutId,确保多次调用时只有最后一次触发。
使用 Lodash 的 _.debounce
实际项目中,为了获得更丰富的功能(如 leading、trailing、cancel 等),推荐使用成熟的工具库 Lodash。
安装命令:
npm install lodash.debounce
import debounce from 'lodash.debounce';
const searchInput = document.getElementById('search');
function onSearch(query) {
console.log('搜索关键词:', query);
}
// leading: 延迟前是否调用,默认 false
// trailing: 延迟后是否调用,默认 true
const debouncedSearch = debounce(onSearch, 300, {
leading: false,
trailing: true
});
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
返回的函数还包含 cancel() 和 flush() 方法,方便取消或立即执行待定调用。
完整示例:防抖搜索组件
下面是一个可直接运行的 HTML 示例,整合了样式与逻辑:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Debounce Demo</title>
<style>
body { font-family: sans-serif; padding: 2rem; }
#results { margin-top: 1rem; }
.item { padding: 0.5rem 0; border-bottom: 1px solid #eee; }
</style>
</head>
<body>
<h1>Debounce 搜索示例</h1>
<input id="search" type="text" placeholder="输入关键词…" autocomplete="off" />
<div id="results"></div>
<script type="module">
import debounce from 'lodash.debounce';
const search = document.getElementById('search');
const results = document.getElementById('results');
async function fetchResults(query) {
return ['苹果', '香蕉', '橘子', '西瓜'].filter(item => item.includes(query));
}
async function handleSearch(query) {
const list = await fetchResults(query);
results.innerHTML = list.map(item => `<div class="item">${item}</div>`).join('');
}
// 300ms 防抖,禁止 leading,允许 trailing
const debouncedHandle = debounce(handleSearch, 300, { leading: false });
search.addEventListener('input', e => {
const q = e.target.value.trim();
if (q) debouncedHandle(q);
else results.innerHTML = '';
});
</script>
</body>
</html>
掌握防抖及其'兄弟'节流(throttle),能让应用在面对频繁交互时依然保持流畅稳定。根据业务需求调整参数,即可实现灵活的性能优化。

