为什么我的无限滚动在快速滚动时会重复加载数据?

Prog.贝贝 阅读 34

我在用Intersection Observer做无限滚动时,当快速拖动滚动条到底部,会触发多次加载请求,导致重复数据。尝试过设置threshold: 0.1和调整rootMargin都没用,控制台显示每次回调都执行了,但数据接口明明还没返回…


const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      fetchMoreData(); // 这个函数会被多次调用
      // 尝试加了断开,但没生效
      observer.unobserve(entry.target);
    }
  });
}, { rootMargin: '0px', threshold: 1.0 });

observer.observe(targetElement);

是不是observer没有及时停止观察?或者需要手动重置某个状态?

我来解答 赞 7 收藏
二维码
手机扫码查看
2 条解答
书生シ誉馨
问题出在没控制好加载状态,快速滚动时接口还没返回就又触发了。懒人方案是加个锁,正在加载时直接return。

let isLoading = false;

const observer = new IntersectionObserver(entries => {
if (isLoading) return;
entries.forEach(entry => {
if (entry.isIntersecting) {
isLoading = true;
fetchMoreData().finally(() => isLoading = false);
observer.unobserve(entry.target);
}
});
}, { rootMargin: '0px', threshold: 1.0 });

observer.observe(targetElement);


这样改完就完事了,别想太多。记得把fetchMoreData包成返回Promise的函数,方便处理finally。
点赞
2026-02-20 04:02
UI尚昆
UI尚昆 Lv1
嗯,这种情况我遇到过不少次。问题出在fetchMoreData()被多次调用,而Intersection Observer本身并没有内置的防抖机制。即使你加了observer.unobserve(entry.target),但如果滚动很快,可能在触发回调时数据还没加载完,就又触发了一次。

解决办法很简单,用一个标志位来控制加载状态:

let isFetching = false;

const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting && !isFetching) {
isFetching = true;
fetchMoreData().then(() => {
isFetching = false;
}).catch(() => {
isFetching = false;
});

observer.unobserve(entry.target);
}
});
}, { rootMargin: '0px', threshold: 1.0 });

observer.observe(targetElement);

function fetchMoreData() {
return new Promise((resolve, reject) => {
// 模拟异步请求
setTimeout(() => {
console.log('数据加载完成');
resolve();
}, 1000);
});
}


这样每次触发加载时,先检查isFetching的状态,如果正在加载就不重复触发了。记得在加载完成后把标志位重置为false,不然后面就永远不会再加载了。

另外,如果你觉得写起来麻烦,插件也可以搞定这种需求,不过自己实现更灵活一些。
点赞 10
2026-01-31 20:05