无限滚动加载时怎么避免重复请求?
我在做商品列表的无限滚动,每次滚动到底部就触发加载下一页,但有时候用户滚太快,会连续发好几次请求,导致数据重复或者接口压力大,咋办?
我试过用一个 loading 状态锁住,但好像还是会有问题,比如:
window.addEventListener('scroll', () => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100) {
if (!isLoading) {
isLoading = true;
fetchMoreData();
}
}
});
但偶尔还是会触发两次,是不是判断条件不够严谨?
最简单的修复是加个节流,把 scroll 事件的频率降下来:
不过更推荐用 IntersectionObserver 来做这个, 比 scroll 事件靠谱多了:
这里关键是放一个看不见的 DOM 元素在列表底部,当它进入视口时就触发加载。
还有个小坑要提醒你:网络请求本身也要做好保护,比如用请求 ID 或者 cancel token,确保先发的请求后返回不会覆盖正确的数据,不过这种情况比较少见,你先用上面两种方法应该能解决个八九不离十。
第一种是加个防抖(debounce),简单粗暴有效:
第二种是更严谨的锁机制,配合请求标记:
个人推荐第一种,简单够用。第二种适合更复杂的场景。还有个隐藏技巧是把触发点调高点,比如改成
document.body.offsetHeight - 300提前触发,给网络请求留缓冲时间。对了,记得在fetch完成后才把isLoading设回false,我见过有人把这个写在fetch前面导致bug的(别问我是怎么知道的...)