长列表分页加载时怎么避免重复请求和数据错乱?
我用 Intersection Observer 做滚动分页加载,但快速滚动时经常触发多次请求,导致后一页的数据比前一页先回来,顺序全乱了。
试过加 loading 锁:if (loading) return;,但还是偶尔出现重复项或者跳页。有没有更稳妥的做法?
这是我的加载逻辑:
const loadMore = async () => {
if (loading || !hasMore) return;
loading = true;
const res = await fetch(<code>/api/items?page=${page + 1}</code>);
const data = await res.json();
items.push(...data.items);
page += 1;
hasMore = data.hasMore;
loading = false;
};
核心思路是:要么强制顺序执行,要么取消过期请求。
最稳妥的做法是用一个请求队列,每次 loadMore 不是直接发请求,而是 push 到队列里,然后串行处理:
这样保证请求按触发顺序依次执行,不会出现顺序错乱。
另一个更狠的做法是用 AbortController,直接取消还在路上的旧请求:
不过 AbortController 这种适合「只保留最新请求」的场景,如果你想保留所有数据还是用队列方案更稳。
还有一个容易漏的点:Intersection Observer 本身也可能触发多次。你需要确保在触发时做下防抖,或者用一个标记表示当前是否已经建立了观察:
其实 loading 锁配合队列基本就能解决 90% 的问题了,代码改起来也不大,优先试试队列方案。