防抖是通过重置定时器实现“最后一次触发后延迟执行”的技术,适用于搜索输入、resize等需响应终态的场景;其核心是清除旧定时器并新建,支持立即执行选项与this绑定。

防抖(Debounce)是一种限制函数执行频率的技术:当某个事件被高频触发时,它会忽略前面的多次调用,只在最后一次触发后等待一段“静默时间”,若期间不再触发,才真正执行函数。
防抖的核心逻辑
它不是“减少调用次数”,而是“重新计时”。每次事件触发,就清除之前的定时器,新建一个。只有连续触发停止后,倒计时走完,函数才运行一次。
- 适合场景:用户输入搜索、窗口大小调整(resize)、鼠标移动(mousemove)等连续触发但只需响应最终状态的操作
- 关键点:必须有“等待期”和“重置机制”,否则就变成节流或普通延时
- 常见误区:把防抖函数直接赋值给事件监听器却忘了传参或绑定 this,导致执行时上下文丢失或参数为空
手写一个可复用的防抖函数
下面是一个带立即执行选项、支持 this 和参数透传的简洁实现:
function debounce(func, wait, immediate = false) {
let timeout;
return function(...args) {
const later = () => {
timeout = null;
if (!immediate) func.apply(this, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(this, args);
};
}
- func:要防抖的目标函数
- wait:等待毫秒数,比如 300 表示“停 300ms 后再执行”
- immediate:为 true 时,首次触发立刻执行,后续触发则重置计时(常用于按钮防重复点击)
- 使用时建议用
const debouncedHandler = debounce(handler, 300)封装后再绑定事件,避免每次触发都新建函数
实际应用示例:搜索框输入优化
未加防抖时,用户每按一个键就发请求,既浪费资源又可能打乱响应顺序;加了防抖后,只在用户暂停输入时查一次:
立即学习“Java免费学习笔记(深入)”;
const searchInput = document.getElementById('search');
const search = (query) => fetch(`/api/search?q=${query}`); // 真实请求逻辑
// 防抖封装
const debouncedSearch = debounce((q) => {
if (q.trim()) search(q);
}, 400);
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
- 输入 “hello” 过程中触发 5 次 input 事件,但只在最后停顿 400ms 后请求一次
hello - 如果用户输到 “hel” 就停下,400ms 后请求的是 “hel”,不会等到 “hello”
- 若需取消待执行请求(如上一个请求还没返回,新请求已发起),应在
fetch中配合AbortController使用
和节流(Throttle)的区别
防抖关注“最后一次”,节流关注“固定节奏”。例如滚动监听:
- 用防抖:用户滚完停下来才执行一次(适合更新页面状态、保存滚动位置)
- 用节流:每 100ms 最多执行一次(适合实时计算滚动进度、懒加载)
- 别混用:想“控制频率”选节流,想“响应终态”选防抖











