一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

节流:闭包实现固定时间频率限制逻辑

时间:2026-06-19 09:47:52 编辑:袖梨 来源:一聚教程网

节流函数必须用闭包封装lastTime和timer状态以实现隔离;时间戳版保频、首次立即执行,适合scroll/resize;定时器版收尾、只执行最后一次,适合搜索/防抖;增强版支持leading/trailing且共用闭包状态;视觉场景优先用requestAnimationFrame。

节流函数要真正实现“固定时间频率限制”,闭包不是可选项,而是必需结构——它把 lastTimetimer 这类状态牢牢锁在独立作用域里,既不被外部干扰,也不与其他节流实例冲突。

为什么必须用闭包封住状态

节流不是简单加个 setTimeout 就完事。它需要两个关键状态持续存在:

  • lastTime:记录上一次真实执行的时间戳,用于判断是否过了间隔期
  • timer:保存当前待执行的定时器 ID,用于清除旧任务、避免重复触发

这两个值不能每次调用都重置,也不能放在全局变量里——否则两个滚动监听器会互相覆盖 timer,或者 resize 和 scroll 共享一个 lastTime 导致节奏错乱。闭包让 throttle(fn, 100) 每次调用都生成专属上下文,状态彼此隔离。

时间戳版:保频型,适合滚动/缩放等稳定采样

逻辑是“首次立刻执行,之后只在间隔达标时再放行”。它不依赖定时器,响应直接,无延时偏差。

  • 每次触发读取 Date.now(),与 lastTime 做差值判断
  • 满足 now - lastTime >= delay 才执行回调,并更新 lastTime
  • 适合 scroll、resize、mousemove 等需“至少每 X 毫秒响应一次”的场景

定时器版:收尾型,适合输入搜索/加载更多

逻辑是“每次触发都重设延迟任务,最终只执行最后一次”。它靠 clearTimeout + setTimeout 协同工作。

  • 首次触发设定时器,delay 后执行
  • 期间重复触发,先 clearTimeout(timer),再设新定时器
  • 执行回调后必须清空 timer = null,防止残留状态干扰下一轮
  • 适合输入框搜索、按钮防连点、滚动到底部加载更多等“松手后才响应”的需求

带 leading/trailing 的增强版:首尾可控,仍靠闭包统一管理

业务常需要更精细控制:拖拽要立刻动(leading),松手后还要补一次加载(trailing)。这不能靠拼凑逻辑,必须由同一闭包维护全部状态。

  • leading: true → 首次调用立即执行,并更新 lastTime
  • trailing: true → 每次调用都尝试设定时器,但只保留最后一个
  • trailing 回调里要二次判断:if (Date.now() - lastTime >= delay),避免和 leading 冲突
  • timerlastTimepending 标志位全在同一个闭包内闭环流转

进阶建议:视觉场景优先用 requestAnimationFrame

如果目标是 DOM 更新流畅(比如吸顶、视差滚动、懒加载),硬写 throttle(fn, 16) 不如用 RAF 闭包:

  • 闭包内维护 isQueued = false,确保同一帧只注册一次 requestAnimationFrame
  • 滚动事件里只做数据采集(如缓存 scrollTop),RAF 回调里再批量更新 DOM
  • 天然对齐浏览器刷新节奏,比固定 delay 更稳定、更省资源

热门栏目