跳到主要内容

节流防抖与延迟装饰器

debounce 与 throttle 作为装饰器怎么写?​

  • debounce(func, ms): 每次调用先清掉上一个定时器再重新计时, 只在停止调用 ms 后执行最后一次, 适合输入结束后统一处理;
  • throttle(func, ms): 首次立即执行, 之后 ms 内忽略调用, 冷却结束时用最后一批参数补发一次, 保证首尾都执行, 适合滚动与鼠标移动;
function throttle(func, ms) {
let frozen = false,
savedArgs,
savedThis;
function wrapper() {
if (frozen) {
savedArgs = arguments;
savedThis = this;
return;
}
frozen = true;
func.apply(this, arguments); // 首次立即转发
setTimeout(() => {
frozen = false;
if (savedArgs) wrapper.apply(savedThis, savedArgs); // 补发末次调用
savedArgs = savedThis = null;
}, ms);
}
return wrapper;
}

延迟装饰器为什么要用箭头函数?​

  • 目标: delay(f, ms) 返回推迟 ms 毫秒执行的包装器;
  • 难点: setTimeout 里的函数由引擎裸调用, 会丢掉包装器的 this 与 arguments;
  • 解法: 内层用箭头函数, 它没有自己的 this/arguments, 于是直接取自外层包装器;
function delay(f, ms) {
return function () {
setTimeout(() => f.apply(this, arguments), ms);
};
}
delay(console.log, 1000)("test"); // 1 秒后输出 test
  • 等价写法: 外层先存 const ctx = this, args = [...arguments], 再在普通函数里使用;