实时聊天消息去重核心是避免重复渲染,而非删除消息;应基于服务端下发的唯一id,用set维护已接收id进行增量校验,兼顾时序、元数据及重连场景,禁用json.stringify比对。

实时聊天消息列表去重,核心不是“把重复消息删掉”,而是“避免重复渲染同一条消息”。直接对整个消息数组调用 Set 去重不仅无效(对象不被识别为重复),还可能破坏时序、丢失元数据。真正高效的做法,是结合消息唯一标识 + 客户端状态管理来实现精准去重。
按消息 ID 做增量去重
每条消息应由服务端下发唯一、稳定的 id(如 UUID 或时间戳+序列号组合)。客户端收到新消息时,只检查该 id 是否已存在,而非比对整个对象:
- 维护一个
Set存储已接收的消息 ID:const seenIds = new Set(); - 在
onmessage中解析后先校验:if (seenIds.has(data.id)) return; - 通过则存入 ID 并更新 UI:
seenIds.add(data.id); messages.push(data);
处理重复推送与网络重连场景
WebSocket 断线重连后,服务端常会补发未确认消息(QoS 1)或重放最近几条,导致前端收到重复 ID 的消息:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 不要依赖连接状态判断是否“可能重复”,统一走 ID 校验流程
- 若业务要求保留“重发标记”,可在去重后记录日志,但不渲染
- 避免在
onclose时清空seenIds——ID 应跨连接生命周期有效
避免用 JSON.stringify 比对对象去重
有人尝试 JSON.stringify(msg) === JSON.stringify(existing) 判断重复,这在实际中不可靠:
- 对象属性顺序不同会导致字符串不同(如
{a:1,b:2}vs{b:2,a:1}) - 函数、
undefined、Symbol 等值会被忽略或报错 - 时间戳字段(如
createdAt)每次都不一样,必然不等 - 性能差:每次都要序列化整个消息对象
配合服务端做语义级去重(进阶)
对于用户撤回、编辑、合并发送等操作,单靠 ID 不够,需服务端协同:
- 撤回消息发
{type: 'recall', originalId: 'xxx'},前端查到对应 ID 就从列表中移除 - 编辑消息用
originalId+version字段,UI 层替换原消息而非新增 - 服务端对同一用户短时间内的多条文本消息自动合并为一条(带折叠展开),前端按
groupId渲染
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










