防抖与节流:高频事件的正确打开方式

陈先生
陈先生 正式会员认证极客
发布于 2026-09-23 04:20 ·1 浏览 ·2 回复
本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-567.html
转载请注明出处,版权归原作者所有。

全部回复 2

yipeng
yipeng 正式会员认证极客 1楼 2026-09-23 04:29

这套代码基本可以直接进项目了,唯一要补的是时间戳

wbcm
wbcm 见习用户 #103 2楼 2026-09-23 04:36
yipeng:这套代码基本可以直接进项目了,唯一要补的是时间戳

对,时间戳版最大的坑就是「尾调用丢失」——滚动到底部那一次如果没跨过 interval,`fn` 就永远不会执行,「加载更多」直接失灵。补法不是加时间戳,而是时间戳 + `setTimeout` 双轨:到点立即执行,没到点就挂一个定时器兜底最后一次。

function throttle(fn, interval = 300, { leading = true, trailing = true } = {}) {
  let last = 0, timer = null;
  function throttled(...args) {
    const now = Date.now();
    if (!last && !leading) last = now;
    const remaining = interval - (now - last);
    if (remaining <= 0) {
      if (timer) { clearTimeout(timer); timer = null; }
      last = now;
      fn.apply(this, args);
    } else if (!timer && trailing) {
      timer = setTimeout(() => {
        last = leading ? Date.now() : 0;
        timer = null;
        fn.apply(this, args);
      }, remaining);
    }
  }
  throttled.cancel = () => { clearTimeout(timer); timer = null; last = 0; };
  return throttled;
}

用法上:滚动加载、输入联想保留 `leading + trailing`;拖拽跟随、鼠标绘制建议 `trailing: false`,否则松手后会「回弹」跳一下。组件卸载记得 `cancel()`,不然定时器可能引用已销毁的 DOM。

一个小注意点:`last` 用 `Date.now()` 就别和 `performance.now()` 混用,两者起点不同会算出负值;另外 `