优先采用服务端游标分页,前端仅追加数据;次选Map增量合并,用id缓存去重;最后才用全量保序去重。核心是去重越靠近数据源头效率越高。

处理前端大规模分页数据时,常遇到重复项问题——比如用户下拉刷新、搜索重试或滚动加载,导致同一数据在不同页中多次出现。直接拼接会引入冗余,影响展示和统计。关键不是“先合并再去重”,而是“合并过程中精准识别并跳过已存在项”。下面几种实用策略,兼顾性能、可读性和兼容性。
按唯一标识(如 id)增量合并
适用于后端返回结构化数据(如 {id: 123, name: "张三", ...}),且每条记录有稳定主键:
- 用
Map缓存已加载项的id → item映射,插入新页数据前逐条检查 - 避免遍历整个历史数组,时间复杂度从 O(n×m) 降至 O(m),m 是当前页长度
- 示例:
const loadedMap = new Map(); // 全局缓存 function mergePage(newData) { const uniqueItems = []; for (const item of newData) { if (!loadedMap.has(item.id)) { loadedMap.set(item.id, item); uniqueItems.push(item); } } return uniqueItems; } // 调用:currentList.push(...mergePage(nextPageData));
服务端配合:传递 last_id 或 cursor
真正减少重复的根本解法是让后端支持游标分页(cursor-based pagination):
- 前端不再依赖页码(page=2),而是传上一页最后一条的
id或加密cursor - 后端保证“从该点之后取 N 条”,天然规避翻页重叠
- 前端无需去重逻辑,仅追加即可,内存与 CPU 开销最小
- 注意:需后端支持;若只提供 offset 分页,此法不可行
客户端智能合并(适合无主键或弱主键场景)
当数据无可靠 id(如纯文本列表、日志片段),可用组合字段生成临时指纹:
将一个或多个 UI 原型图、线框图、产品截图或设计稿转换为标准化、可直接交付的 PRD 风格文档,供产品、设计、前端和测试共同使用。适用于 Codex 需要分析 PC 网页、桌面端、移动端、响应式页面、独立弹窗、表单、表格、看板、数据大屏或多页面流程截图,还原页面结构与交互,强制套用固定文档模板,抽取跨页面共享规则,或把一组原型沉淀为单页规范文档加整体业务流程文档的场景。不适用于纯视觉审美点评、代码实现、接口设计、埋点方案、竞品分析或无 UI 输入的业务需求创作。
立即学习“前端免费学习笔记(深入)”;
- 对关键字段(如
title + timestamp + content.slice(0,50))做简单哈希(如JSON.stringify后取slice(0,32))作为 key - 仍用
Map缓存指纹,避免深比较 - 慎用于长文本或高频更新场景,哈希碰撞风险需结合业务容忍度评估
批量去重 + 保序合并(兼容老环境)
若必须使用传统分页(offset)且无法改服务端,又需兼容 IE11 等旧浏览器:
- 将所有分页数据暂存为扁平数组,用
reduce+findIndex保序去重 - 不推荐直接
Set,因对象引用不等价,且会丢失顺序 - 示例:
function mergeWithDedupe(allPages) { return allPages.flat().reduce((acc, cur) => { if (!acc.find(item => item.id === cur.id)) acc.push(cur); return acc; }, []); } - 注意:仅适用于总数据量可控(如 ≤ 5000 条),否则性能明显下降
实际项目中,优先推动后端支持 cursor 分页;次选 Map 增量合并;仅在受限条件下才用全量保序去重。核心原则是:去重动作越靠近数据源头,整体效率越高。

















