无限滚动加载时怎么避免重复请求?

Designer°瑞君 阅读 4

我在做商品列表的无限滚动,每次滚动到底部就触发加载下一页,但有时候用户滚太快,会连续发好几次请求,导致数据重复或者接口压力大,咋办?

我试过用一个 loading 状态锁住,但好像还是会有问题,比如:

window.addEventListener('scroll', () => {
  if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100) {
    if (!isLoading) {
      isLoading = true;
      fetchMoreData();
    }
  }
});

但偶尔还是会触发两次,是不是判断条件不够严谨?

我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
端木艺菲
哈哈这个坑我也踩过!你那个方案思路是对的,但确实可能被快速滚动触发多次。我给你两个实用的改进方法:

第一种是加个防抖(debounce),简单粗暴有效:
let debounceTimer;
window.addEventListener('scroll', () => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100 && !isLoading) {
isLoading = true;
fetchMoreData();
}
}, 200); // 200ms内连续滚动只触发一次
});


第二种是更严谨的锁机制,配合请求标记:
let loadingLock = false;
let currentPage = 1;

async function fetchMoreData() {
if (loadingLock) return;
loadingLock = true;

try {
const data = await fetch(/api/data?page=${currentPage});
// 处理数据...
currentPage++;
} finally {
loadingLock = false;
}
}


个人推荐第一种,简单够用。第二种适合更复杂的场景。还有个隐藏技巧是把触发点调高点,比如改成 document.body.offsetHeight - 300 提前触发,给网络请求留缓冲时间。

对了,记得在fetch完成后才把isLoading设回false,我见过有人把这个写在fetch前面导致bug的(别问我是怎么知道的...)
点赞
2026-03-10 13:01