Frontend / Full Stack SWE · Frontend / System Design

ChatGPT式前端:流式回复、组件状态与持久恢复

网络chunk不是完整消息,UI需要请求身份和可恢复的事件序列。

题目重点:网络chunk不是完整消息,UI需要请求身份和可恢复的事件序列。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练聊天产品前端,不调用或描述某实际产品私有API。流式协议事件有conversation/message/request ID、sequence、delta/done/error。
  • server为持久历史权威,浏览器草稿与临时UI状态本地保存;typing效果不应伪装已经收到未生成内容。

解题路线

  1. 组件划为ConversationList、MessageList/Message、Composer、StreamStatus与Retry控件。normalized数据按conversation/message ID保存,显示顺序单独数组,避免整个消息树每chunk重复复制。
  2. 提交message带client_request_id,临时user message和assistant placeholder关联request。收到delta只更新对应message,seq去重/检查缺口;换conversation不能让旧请求delta进入新窗口。
  3. transport可SSE单向server stream或WebSocket双向,UTF-8/协议frame可能跨网络chunk,需要增量decoder及frame buffer。done是应用状态,连接关闭未必完成;error保留已有内容但明确未完成。
  4. token更新可buffer并按帧或短周期flush到render state,避免每字符重排全部列表。显示内容存在state,连接/abort controller/flush timer可放ref;ref改变不触发render,不能只改ref希望屏幕更新。
  5. 持久化区分已确认消息、partial回复与草稿,重载先拉server snapshot再从last_seq续流;若协议无resume则标interrupted并由用户决定重试,不能自动拼新生成内容当旧回复。sanitize/render边界、权限和storage敏感性独立处理。

手动走一遍

用户发m后立刻切到另一conversation,旧stream仍按message ID存原会话,不覆盖当前回复。网络每次chunk50bytes,可能把一个UTF-8字符或SSE frame拆开;不能对单chunk做JSON.parse。连接断开有partial文本但无done,UI显示中断及可重试,不误报成功。

规模与取舍

N消息、C流事件,增量更新应随相关文本/可见列表规模;全文Markdown每chunk重解析会累计近似二次成本。大历史虚拟列表减少DOM,持久partial写盘需节流;内存/本地空间设保留上限。

易错点与追问

容易失分的边界

  • 连接断开就标回复完成。
  • 所有delta追加到当前屏幕最后消息,切会话时串消息。
  • 将DOM每字符动画成本忽略。

继续深挖

  • 流resume、用户取消和服务端仍运行怎样协商?
  • 多设备编辑同草稿与已确认消息怎样区分冲突策略?

技术参考

  • React useState:技术语义参考,具体题目按本文约定。
  • React useRef:技术语义参考,具体题目按本文约定。
✓已复制微信号!