防抖和节流函数封装的核心是用闭包保存定时器状态,api设计强调语义清晰、this和参数不丢失;防抖支持leading/trailing配置控制执行时机,节流默认leading为true、trailing为false以保证稳定节奏。

防抖和节流函数封装的核心,是用闭包保存定时器状态(如 timer 或 mark),让每次调用返回的函数能“记住”上一次的状态。API 设计的关键不是堆参数,而是让调用者直觉清晰、可读性强、this 和参数不丢失。
防抖函数 API:debounce(fn, delay, options?)
基础签名应支持「延迟执行 + 取消重置 + this 绑定 + 参数透传」。推荐带配置对象的扩展形式:
- fn:必传,要防抖的原函数
-
delay:必传,毫秒数,比如
300 - options.leading:布尔值,是否立即执行第一次(即“首次触发立刻执行,后续连续触发只响应最后一次”)
- options.trailing:布尔值,是否在停止触发后执行(默认 true,对应经典防抖行为)
这样设计的好处是语义明确,比如 debounce(api.search, 500, { leading: false, trailing: true }) 一眼可知是纯尾部执行;而 { leading: true, trailing: false } 就适合按钮点击——点下就发请求,连点无效。
节流函数 API:throttle(fn, delay, options?)
节流更强调“稳定节奏”,API 风格与防抖对齐,但语义不同:
- fn:同上
- delay:同上
- options.leading:是否在首次触发时立即执行(默认 true)
- options.trailing:是否在周期结束时补一次执行(默认 false,避免滚动中冗余触发)
例如 throttle(handleScroll, 100, { leading: true, trailing: false }) 表示:滚动开始立刻处理一次,之后每 100ms 最多再执行一次,不补尾。
闭包结构必须保证三点
所有封装都依赖闭包维持内部变量,但结构要干净:
-
定时器变量(
timer或timeoutId)不能暴露给外部,只能在返回函数内读写 -
每次调用
debounce()或throttle()都生成独立闭包,互不干扰(比如两个输入框分别防抖,彼此 timer 不冲突) -
内部函数必须用
fn.apply(this, args)或fn.call(this, ...args)转发上下文和参数,否则事件监听里this会变成window,event对象也传不进去
一个轻量但完整的 debounce 示例
不依赖第三方,直接可用:
function debounce(fn, delay, options = {}) {const { leading = false, trailing = true } = options;
let timer = null;
let lastCall = 0;
return function (...args) {
const now = Date.now();
const shouldInvoke = leading && !timer;
if (shouldInvoke) {
fn.apply(this, args);
}
if (trailing) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
}
};
}
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











