防抖函数可通过挂载cancel方法实现手动取消定时器,核心是保存并清除setTimeout返回的timer;支持leading时cancel仅影响延迟执行部分;建议在组件卸载时调用cancel防止内存泄漏。

防抖函数本身不自带“立即停止执行”的能力,但可以通过在返回的防抖函数上挂载一个 cancel 方法来实现手动取消待执行的定时器。核心思路是:保存 setTimeout 的返回值(即定时器 ID),并在需要时调用 clearTimeout 清除它。
1. 基础防抖 + cancel 接口实现
标准防抖函数封装后,暴露 cancel 方法供外部调用:
示例代码:
function debounce(fn, delay) {
let timer = null;
const debounced = function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
// 挂载取消方法
debounced.cancel = function () {
if (timer !== null) {
clearTimeout(timer);
timer = null;
}
};
return debounced;
}
// 使用
const handleSearch = debounce(() => console.log('搜索请求已发出'), 300);
handleSearch(); // 触发,300ms 后执行
handleSearch.cancel(); // 立即清除,不会执行
2. 支持立即执行(leading)时的 cancel 注意点
如果防抖支持首次立即执行(如 Lodash 的 { leading: true }),cancel 只能取消后续延迟执行的部分,无法撤回已经立即执行过的调用。因此 cancel 的语义始终是「取消尚未触发的那次执行」。
关键逻辑:
- 立即执行分支不依赖定时器,所以无需也不可被 cancel 撤销
- 只有
setTimeout分支受cancel影响 - 需确保
timer在立即执行后被重置(否则可能误清下一次定时器)
3. 更健壮的 cancel 实现(带执行状态追踪)
为避免重复 cancel 或在 fn 执行后仍尝试 clear,可增加执行标记:
function debounce(fn, delay) {
let timer = null;
let isPending = false;
const debounced = function (...args) {
if (!isPending) {
isPending = true;
// 首次触发可选立即执行(按需开启)
// fn.apply(this, args);
}
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
isPending = false;
}, delay);
};
debounced.cancel = function () {
clearTimeout(timer);
timer = null;
isPending = false;
};
return debounced;
}
4. 实际使用建议
- 在组件卸载(如 React
useEffectcleanup、VuebeforeUnmount)时务必调用debounced.cancel(),防止内存泄漏或对已销毁上下文的调用 - 不要在防抖函数内部直接调用
cancel—— 它是给外部控制用的接口 - 若需多次复用同一防抖逻辑,每次调用
debounce都会生成独立的timer和cancel,互不影响
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











