<p>节流是为了防止 scroll 事件高频触发导致重复请求、卡顿或渲染压力,核心是控制触底判断调用频率;需用 document.documentElement 获取滚动和尺寸值,触底条件为 scrollY + clientHeight >= scrollHeight - threshold;节流应作用于 scroll 回调函数,间隔 100~200ms,不可用防抖替代;须配合 loading 状态锁防止重复请求,并在卸载时移除监听器避免内存泄漏。</p>

节流不是为了“更准地判断触底”,而是防止 scroll 事件高频触发导致重复请求、卡顿或渲染压力。触底判断本身是静态计算,关键在控制它被调用的频率。
触底判断的核心公式要写对
必须用 document.documentElement 获取滚动和尺寸值,否则 Safari 等浏览器中 body.scrollTop 始终为 0,判断永远失效:
-
window.scrollY或document.documentElement.scrollTop—— 当前滚动距离 -
window.innerHeight或document.documentElement.clientHeight—— 视口高度 -
document.documentElement.scrollHeight—— 整页内容总高度 - 触底条件:
scrollY + clientHeight >= scrollHeight - threshold(threshold 通常设 100~200)
节流函数要作用在 scroll 回调上,不是 onScroll 本身
直接给 addEventListener('scroll', handler) 加节流,而不是在 handler 里再套一层节流逻辑。推荐使用成熟节流库(如 throttle-debounce),或手写简易版:
- 节流间隔建议 100~200ms:太短起不到限制作用,太长会延迟加载感知
- 不要用防抖(debounce)替代节流:防抖会在停止滚动后才执行,用户快速滚到底部可能错过触发
- 节流后的回调里再做触底判断,避免每次滚动都计算,但又确保足够及时
配合 loading 状态锁,双重防护
节流只管调用频率,不解决请求并发问题。必须加状态控制:
立即学习“Java免费学习笔记(深入)”;
- 定义
let loading = false,每次进入加载逻辑前检查并置为 true - 请求完成(无论成功失败)后才重置
loading = false - 即使节流后仍可能因快速滚动多次进入,loading 锁能彻底拦截重复请求
滚动监听要记得清理
页面卸载或组件销毁时,必须移除 scroll 监听器,否则造成内存泄漏:
- 保存监听器引用:
const scrollHandler = throttle(150, handleScroll) - 绑定:
window.addEventListener('scroll', scrollHandler) - 卸载时:
window.removeEventListener('scroll', scrollHandler) - React/Vue 等框架中,在 useEffect/onUnmounted 中统一管理


















