前端使用websocket通信,当10个用户同时发送10条消息向同一个客户发送消息时,如何处理?
你正在开发的聊天应用,突然间,10个不同的用户,每人发了10条消息(总共100条消息)几乎同时到达你的前端。
你正在开发的聊天应用,突然间,10个不同的用户,每人发了10条消息(总共100条消息)几乎同时到达你的前端。
以下是前端应该如何处理这个“消息风暴”的详细步骤:
第一阶段:接收与缓冲(毫秒级响应)
这一阶段的目标是快速接收所有消息,不阻塞任何UI操作。
- 建立缓冲区:你的应用内部有一个“消息缓冲区”(就是一个临时的数组或队列)。
- 监听并接收:WebSocket 的
onmessage监听器被触发。每当一条消息(共100条)到达时,监听器只做一件事:把这条原始消息原封不动地扔进缓冲区。 - 调度处理器:在第一条消息进入缓冲区后,立即向浏览器调度一个“批处理任务”。这个任务不会马上执行,而是告诉浏览器:“嘿,等你有空的时候(通常是下一帧渲染前),请运行我的消息处理函数。” 这样做可以防止100次消息到达触发100次连续的、阻塞性的处理。
结果:100条消息在极短时间内被安全地存放在缓冲区里,用户界面(UI)在此期间完全流畅,用户甚至可以继续滚动或点击。
第二阶段:处理与更新状态(数据层面)
现在,浏览器空闲下来,开始执行我们调度的“批处理任务”。
- 锁定缓冲区:处理函数首先查看缓冲区,发现里面有100条新消息。它将这些消息一次性全部取出。
- 遍历与分类:处理函数开始遍历这100条消息。对于每一条消息,它会:
- 解析消息内容(比如从JSON字符串转换为JavaScript对象)。
- 识别消息的发送者(例如,用户A、用户B等)。
- 更新中央数据模型:你的应用有一个“中央数据模型”或“状态”,它用JavaScript对象记录了所有对话的信息。处理函数会根据每条消息去更新这个模型:
- 找到对应的对话:根据发送者ID,在数据模型中找到对应的对话记录。如果这是个新用户的首条消息,就创建一个新的对话记录。
- 追加消息:将这条新消息添加到该对话的“消息列表”数组末尾。
- 更新对话预览:更新该对话的“最后一条消息”预览文本。
- 更新未读数:检查这条消息所属的对话是否是当前用户正在查看的。
- 如果不是:将该对话的“未读消息数”加一。
- 如果是:未读数不变(因为用户正在看,所以不算未读)。
- 记录变更:在更新数据模型的同时,用一个集合(Set)记录下所有被这次批处理任务修改过的对话的ID(在这个场景下,是10个用户ID)。这至关重要,因为它告诉我们接下来只需要更新UI上与这10个对话相关的部分。
结果:应用的内部数据模型现在已经完全是最新状态了。所有10个对话都包含了新的10条消息,并且未读数也已正确计算。这个过程完全在内存中进行,速度非常快,不涉及任何界面渲染。
第三阶段:渲染与呈现(UI层面)
数据更新完毕,现在是时候让用户看到变化了。渲染过程会根据第二阶段记录的“变更ID集合”来精确地、批量地更新UI。
场景一:用户在“消息列表”界面
- 遍历变更:渲染函数会遍历那10个被修改过的对话ID。
- 定位列表项:对于每个ID,它会在消息列表的DOM中找到对应的列表项(比如,一个
<div>)。 - 批量更新内容:
- 更新该列表项的“最后一条消息”预览文本。
- 更新“未读消息数”的角标(Badge)。如果原来没有角标,就创建一个;如果原来有,就更新数字。
- (可选)重新排序:将这10个更新过的对话列表项移动到列表的最上方,并根据最后一条消息的时间进行排序,确保最新的对话在最顶端。这个移动操作也是批量完成的,以减少对DOM的扰动。
用户看到的效果:10个用户的头像/名字条目几乎同时闪烁了一下,它们的预览消息和未读数都更新了,并可能瞬间移动到了列表顶部。整个过程看起来像一次平滑的动画,而不是100次独立的、卡顿的更新。
场景二:用户正打开了其中一个用户的“聊天界面”(例如,与用户A的聊天)
假设用户正在和用户A聊天,而此时10个用户(包括用户A)的消息都来了。
- 更新消息列表(背景中):首先,完全按照场景一的步骤,更新背景中的消息列表。这部分UI虽然用户当前可能看不到(如果聊天界面是全屏的),但其数据和DOM状态仍然需要保持同步。用户A的列表项未读数不会增加,而其他9个用户的列表项未读数会各自增加10。
- 更新当前聊天窗口:
- 渲染函数检查到“当前打开的对话ID”(即用户A的ID)包含在“变更ID集合”中。
- 它会获取用户A对话记录中新增的10条消息。
- 智能滚动判断:在添加新消息前,先检查聊天窗口的滚动条是否在最底部。
- 批量追加消息:将这10条新消息的DOM元素一次性地、批量地添加到聊天记录的末尾。
- 执行滚动:如果之前判断出滚动条在最底部,那么在添加完新消息后,自动将滚动条平滑地滚动到新的最底部,让用户能看到最新消息。如果用户之前正在向上翻阅历史记录,则不滚动,避免打扰用户。
用户看到的效果:
- 当前与用户A的聊天窗口中,连续出现了10条新消息,窗口平滑地向下滚动(如果适用)。
- 如果此时用户返回到消息列表,会看到其他9个用户的对话都带上了红色的“10”未读角标,并排在了列表顶部。
通过这三个接收-处理-渲染的分离步骤,前端应用可以从容应对大规模的并发消息,既保证了数据的准确性,又提供了流畅、不卡顿的用户体验。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)