长列表分页加载时如何避免重复请求和数据错乱?

UP主~艺菲 阅读 4

我在做商品列表的分页加载,每次滚动到底部就调用接口拉下一页数据。但有时候网络慢,用户快速滚动会触发多次请求,导致数据重复或者顺序错乱,咋办?

我试过加个 loading 锁:if (loading) return;,但偶尔还是会出现重复项,特别是用户快速上下滚动的时候。

const loadMore = async () => {
  if (loading || !hasMore) return;
  loading = true;
  const res = await fetch(<code>/api/items?page=${page}</code>);
  items.push(...res.data);
  page++;
  loading = false;
};
我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
俊俊~
俊俊~ Lv1
这问题太常见了,我之前也被坑过。你那个loading锁其实不够,我给你说几个关键点:

第一,前端这边需要双重保险。除了loading状态,还要加个lastRequestId来标记最近一次请求。这样就算用户疯狂滑动,也能保证只处理最后一次请求的结果:

let lastRequestId = 0;
const loadMore = async () => {
if (loading || !hasMore) return;

loading = true;
const currentRequestId = ++lastRequestId;

try {
const res = await fetch(/api/items?page=${page});
// 只处理最新请求的结果
if (currentRequestId === lastRequestId) {
items.push(...res.data);
page++;
}
} finally {
loading = false;
}
};


第二,服务端最好也做防重处理。给分页接口加个timestamp参数,超过5秒的旧请求直接拒绝。这样能避免网络延迟导致的乱序问题。

第三,实在不放心的话,可以在合并数据前做去重判断。比如商品列表可以用id检查是否已存在。不过这个算是兜底方案了,前面两个处理好基本够用。

还有个细节,page++最好放在数据合并成功之后,避免请求失败时页码错位。
点赞
2026-03-06 02:09