跳到正文
posts

重新理解流式渲染问题

June 24, 2026

最近在准备面试,刷到一道题:React 怎么接 LLM 的流式输出?怎么避免每个 token 都触发一次渲染?

我去问 AI,AI 一口气给了 4 个解法。

不出意外,看完一个都记不住。我突然意识到是我问法有问题。

换了个问法

我又回去问 AI:"这类问题背后有没有一个更通用、抽象的思考方式?"

这次我得到了一个新角度:流式输出的生产-消费速率不匹配问题。

LLM 的输出是不确定的——快的时候一帧来 5 个 token,慢的时候几百毫秒才给一个。UI 的渲染节奏是相对稳定的(一秒 60 帧),所以需要主动控制渲染节奏。

跨域一看,原来早就有解法

顺着这个思路往下想,我发现一件事:前端流式渲染和服务端任务队列其实是同一个问题

  • 服务端 AIGC 视频生产:生产端(前端应用)一秒创建 100 条视频生成任务,但消费端(视频模型 厂商)只能并发 5 条。怎么办?塞进队列。
  • 前端 LLM 流式输出:上游一秒能吐几百个 token,但渲染端只想要「匀速显示」。怎么办?塞进缓冲。

两个场景,抽象出来是同一件事

上游生产 > 下游消费 → 中间需要一个缓冲层来吸收抖动。

意识到这一点的时候,我有种一通百通的感觉: 日志、鼠标事件、WebSocket 消息……凡是「上游快、下游慢」的场景,都符合这个问题

第三步:拆出三层模型

把流式问题拆开看,其实就是三层:

┌─────────────┐

   Source      不可控,节奏未知

  (数据源)      接口:onData(chunk)

└──────┬──────┘

       

┌─────────────┐

   Buffer      解耦两层,允许短期速率不匹配

  (缓冲层)    

└──────┬──────┘

       

┌─────────────┐

   Pacing      可控,按目标节奏拉

  (消费层)      决定 UI 怎么呈现

└─────────────┘

任何流式问题,先问自己这三层各自的最优策略是什么,能不能独立替换。

回到 React 流式渲染:

  • Source 层:LLM 给的 ReadableStream,收集就好。
  • Buffer 层:用 useRef 暂存 token,让 Source 和 React 不直接挂钩。Ref 不触发渲染。
  • Pacing 层:定时器(setInterval / requestAnimationFrame)按 50ms 节奏拉一次,触发 setText。就不会疯狂渲染。

这三层必须物理分开。一旦把「数据」和「渲染」耦合在一起(最常见的就是直接 setState(text + chunk)),屎山就出现了。

具体 API 都是细节

到这一步,「用 useRef 还是 useSyncExternalStore」「setInterval 还是 rAF」就只是细节了。

  • 多组件共享同一个流?把 Buffer 提到 React 外面(Zustand),订阅用 useSyncExternalStore
  • 流式内容是 markdown?Pacing 层要感知「块级边界」,不能在 ** 中间断开。
  • 要暂停/恢复/回看?Buffer + 游标,类似 offset 概念。
  • 断线重连?Buffer + 快照 + 重放,已消费的 chunk 序列化成可重放事件。

每加一个需求,就在一层加一个适配器。加完要重写,说明分层错了;只是加一个文件,说明分层对。

面试到底在考什么

回头看这道题,我意识到面试官不想听 API。面试官想听的是你思考问题的结构

万能答题模板:

这其实是生产-消费速率不匹配问题。LLM 是信源,UI 是信宿,中间是有限缓冲的不稳定信道。借鉴 Jitter Buffer 的思路,把数据源和渲染节奏解耦——Source 推入 buffer,Pacing 定时拉取。React 在这个模型里只是 Pacing 层的渲染器,可以随时替换。

30 秒说完。面试官听到的是「这人脑子里有东西」,不是「这人背了题」。

这套思路是怎么来的

回头想,我其实只做了一件事:在拿到答案之前,先问「这个问题的本质是什么」。

不是所有问题都值得这么问。但凡是面试里被反复考的「套路题」,背后几乎都有一个跨域通用的模型。要做的就是记住这个模型。

给自己的练习方法

  1. 丢掉技术栈:「如果换成 Vue / Flutter / iOS,这个问题还存在吗?」如果存在,说明不是技术问题,是通用问题。
  2. 找跨域对照:「这个问题的解法,在别的领域叫什么?」比如「流式渲染」= Jitter Buffer,「前端缓存」= Cache,「状态管理」= State Machine。
  3. 问「为什么是这个解法」:每个解法背后,是哪些约束?

写在最后

准备面试 真正有用的是训练自己看到问题本质的能力

这件事 AI 帮不了太多。AI 可以给你答案,但「问出好问题」得自己来。


相关文章

  • 配套 demo:/demo/llm-stream-render-comparison(用 Ref + setInterval 实现「匀速渲染」)