首次点击立即执行、后续点击防抖的实现方式是:设isFirst标志位,首次调用时立即执行并置false,之后每次先清除定时器再新建延时;支持immediate=true参数和cancel重置方法。

防抖函数默认会延迟执行,所以第一次点击不会立即触发。要实现“首次点击立即执行,后续连续点击防抖”,只需在防抖逻辑中加一个判断:如果是第一次调用,就立刻执行;之后的调用才进入防抖流程。
核心思路:用标志位区分首次调用
定义一个 isFirst 标志,默认为 true。第一次调用时直接执行函数并重置标志位为 false;之后每次调用都先清除已有定时器,再重新设置延时执行。
- 首次调用 → 立即执行 + 将 isFirst 设为 false
- 非首次调用 → 清除上一次定时器 + 启动新定时器
简易实现(无依赖)
下面是一个可直接使用的防抖函数,支持首次立即执行:
function debounce(func, wait, immediate = false) {
let timeout = null;
let isFirst = true;
return function executedFunction(...args) {
const later = () => {
timeout = null;
if (!immediate) func.apply(this, args);
};
if (immediate && isFirst) {
func.apply(this, args);
isFirst = false;
} else {
clearTimeout(timeout);
timeout = setTimeout(later, wait);
}
};
}
使用示例:
// 点击按钮,第一次立刻执行,之后按 300ms 防抖button.addEventListener('click', debounce(() => console.log('clicked'), 300, true));
注意点:immediate 参数的语义
这里 immediate = true 表示“首次立即执行”,和 Lodash 的 debounce(func, wait, { leading: true }) 行为一致。别混淆成“每次开头都执行”——它只在第一次调用时生效,后续仍受防抖控制。
立即学习“Java免费学习笔记(深入)”;
- 如果希望每次“新一段连续操作”的开头都执行(比如用户停顿后再点),要用 leading + trailing 组合,但那就不是纯首次了
- 单次页面生命周期内,isFirst 只在第一个调用时为 true,之后永远 false
进阶:支持重置(可选)
有些场景需要手动重置状态,比如切换 tab 后想让下一次点击再次“立即执行”。可以暴露一个 cancel 方法来清空定时器并重置标志位:
function debounce(func, wait, immediate = false) {
let timeout = null;
let isFirst = true;
const debounced = function executedFunction(...args) {
const later = () => {
timeout = null;
if (!immediate) func.apply(this, args);
};
if (immediate && isFirst) {
func.apply(this, args);
isFirst = false;
} else {
clearTimeout(timeout);
timeout = setTimeout(later, wait);
}
};
debounced.cancel = () => {
clearTimeout(timeout);
timeout = null;
isFirst = true; // 重置首次标志
};
return debounced;
}
调用 debounced.cancel() 后,下次调用又会立即执行。


















