封装通用工具函数需要分别处理防抖(debounce)和节流(throttle),核心在于利用闭包保存定时器或时间戳,并在返回的包装函数中根据触发时机决定是否执行原函数。对于防抖,通常使用 `settimeout` 延迟执行并清除之前的定时器;对于节流,则通过记录上次执行时间戳来判断是否达到间隔阈值。这两个函数都支持配置选项,如立即执行、最大等待时间等,以便适应不同的业务场景。

如何实现带取消功能的防抖函数
实现防抖的关键是确保在高频触发时只执行最后一次调用,可以通过返回一个包含 `cancel` 方法的对象来增强实用性。具体做法是使用 `setTimeout` 设置延迟,每次触发时清除上一次的定时器并重新设置,同时暴露 `cancel` 方法供外部手动取消 pending 的执行。这样在处理窗口 resize 或搜索输入时,既能避免频繁计算,又能允许用户主动中断等待过程。

function debounce(fn, delay = 300, immediate = false) {
let timer = null;
let isImmediate = false;
const debounced = function (...args) {
const context = this;
if (isImmediate) {
fn.apply(context, args);
isImmediate = false;
} else {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
}
};
debounced.cancel = function () {
clearTimeout(timer);
timer = null;
};
return debounced;
}
上述代码定义了一个 `debounce` 函数,接收目标函数 `fn`、延迟时间 `delay` 和是否立即执行 `immediate` 参数。返回的 `debounced` 函数内部维护了 `timer` 引用,每次调用时若为立即模式则直接执行并标记状态,否则清除旧定时器并设置新定时器。此外,`debounced` 对象挂载了 `cancel` 方法,用于清空定时器并重置状态,确保未执行的回调不会触发。
立即学习“Java免费学习笔记(深入)”;
如何实现支持最大间隔的节流函数
节流旨在限制函数的执行频率,常用策略是记录上次执行的时间戳,只有当当前时间与上次时间之差大于设定间隔时才执行。为了优化体验,可以加入 `maxWait` 参数,确保即使持续触发,函数也能在最长等待时间后强制执行一次。这种实现方式适合处理滚动事件或按钮点击,既能降低负载,又不会让用户感觉响应迟钝。

function throttle(fn, interval = 300, maxWait = null) {
let lastTime = 0;
let timer = null;
const throttled = function (...args) {
const context = this;
const now = Date.now();
const remaining = interval - (now - lastTime);
if (lastTime === 0 || remaining <= 0) {
if (timer) {
clearTimeout(timer);
timer = null;
}
lastTime = now;
fn.apply(context, args);
} else if (maxWait && (!timer || now - lastTime >= maxWait)) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
lastTime = Date.now();
fn.apply(context, args);
timer = null;
}, remaining);
}
};
throttled.cancel = function () {
clearTimeout(timer);
timer = null;
lastTime = 0;
};
return throttled;
}
该 `throttle` 函数通过比较当前时间与 `lastTime` 来计算剩余等待时间 `remaining`。如果满足执行条件(首次调用或间隔已过),则立即执行并更新时间戳;如果设置了 `maxWait` 且距离上次执行已超过最大等待时间,则启动定时器在剩余时间内强制执行。返回的 `throttled` 函数同样提供 `cancel` 方法以清理定时器并重置状态,保证资源释放。
如何处理防抖函数中的上下文丢失问题
在封装防抖函数时,必须注意 `this` 指向和参数传递的问题。如果在返回的包装函数中没有正确绑定 `this` 和传递 `arguments`,会导致原函数执行环境错乱。解决方法是在包装函数内部使用 `apply` 或 `call` 显式指定上下文,并将可变参数数组展开传入。这样可以确保无论在哪里调用防抖后的函数,其内部的 `this` 都能正确指向调用者,参数也能完整保留。


















