Skip to content

流式渲染 ​

TokUI 的核心能力是流式增量渲染:解析器基于状态机,输入一个字符就能推进状态,无需等待完整字符串。这让 AI 逐 Token 输出时,前端能边收边画。

状态机解析 ​

解析器在三个状态间切换:

状态含义
TEXT普通正文,原样输出为文本节点
TAG_OPEN遇到 [,正在读取开标签的属性与内容
TAG_CLOSE遇到 [/,正在读取闭标签

由于状态可中途暂停,任意位置切断的输入都能正确处理 —— 这是流式安全的基础。

feed() 增量 API ​

js
const tokui = new TokUI.TokUI({ container: '#app' });
tokui.startStream();          // 进入流式模式
tokui.feed('[card tt:');
tokui.feed('流式卡片]');
tokui.feed('[p 内容边到边渲染]');
tokui.feed('[/card]');
tokui.endStream();            // 结束流式,刷出缓冲区残余
  • startStream(container?):开启流式,可指定挂载点。
  • feed(chunk):喂入一个分片,立即增量解析并渲染。
  • endStream():结束流式,刷出缓冲区内未闭合的内容。
  • 构造函数 onEvent(type, data) 回调接收 'streamEnd' 等事件。

SSE 接入 ​

connect() 封装了 EventSource,对接服务端 SSE:

js
const tokui = new TokUI.TokUI({
  container: '#chat',
  onEvent: (type, data) => {
    if (type === 'streamEnd') console.log('完成');
  },
});
tokui.connect('/api/chat', { prompt: '画一个登录卡片' });

SSE 协议约定:

  • 每个 data: 行内为 JSON,取其中的 tokui 字段作为 DSL 分片喂给解析器。
  • [DONE] 标记流结束。

服务端可用 TokUIBuilder.toChunks() 把 DSL 切成分块数组,逐块 data: 推送。

1[think open tt:思考过程]
2 用户想要登录卡片,需要用户名、密码、提交按钮…
3[/think]
4[card tt:登录]
5 [input l:用户名 ph:请输入 req]
6 [pwd l:密码 ph:请输入 req]
7 [btn tx:登录 v:primary sub:login block]
8[/card]
加载 TokUI…
TokUI DSL · 左代码右渲染

流式渲染优先级(组件如何流) ​

不同组件在流式下表现不同,按"用户体验"分三档:

档行为组件
① 真流式(边到边渲染)内容逐字/逐格渐显容器内文本([card]文[/card]、[callout]文[/callout]、[p]文[/p]、list/item);[tr] cell 级;[chart] 预览重绘;表格操作列 btn: 逐钮;[thead]/[tbody]
② 骨架占位→转正开标签到达即挂 .tokui-stream-skeleton 脉冲占位,] 到达原地 swap 为真节点纯自闭合大块:stat img avatar result empty video audio file attach commit
③ 一次性 pop-in] 处整渲染(无占位)小件:tag badge dot btn a progress rate slider switch input pwd h1~h6(短) hr 等

大文本组件:优先容器模式(真流式) ​

callout / code / md / terminal / diff 等同时支持自闭合与容器两种写法。流式场景优先容器模式——文本逐字渐显,而非 ] 处一次性 pop-in:

# 自闭合(pop-in,文本不流)——能力保留,适合一次性渲染
[callout t:info tx:"一段较长的说明文字..."]

# 容器模式(真流式,文本逐字)——流式场景推荐
[callout t:info]一段较长的说明文字...[/callout]
[code lang:js]const x = 1;[/code]
[md]## 标题
正文逐字流式...[/md]

字面方括号:容器模式内 [xxx] 会被解析为子组件。若文本需显示字面 [img],用全角括号 [img] 或改自闭合 tx:"...[img]..."(引号内为字面)。

纯自闭合大块:自动骨架占位 ​

stat/img/avatar/result/empty/video/audio/file/attach/commit 无法容器化,流式期框架自动挂骨架占位(无需写法改动),] 到达平滑替换为真节点,避免空洞 pop-in。小件(tag/btn 等)保持 pop-in(骨架一闪反不如直接出)。

流式入场动画(streamAnimation) ​

流式挂载的顶层组件默认带 tokui-fade-in 淡入:动画只动 opacity(无位移),且仅顶层元素挂载——嵌套子元素与纯文本分片不挂,避免每个 token 都播一遍动画。大对话 / 高频流式场景可整体关闭:

js
const tokui = new TokUI.TokUI({ container: '#app', streamAnimation: false });

streamAnimation(默认 true)只作用于流式路径,一次性 render() 的入场动画不受影响。

资源防护 ​

为防止恶意或超长输入耗尽资源:

  • maxBuffer(默认 1MB):单次解析缓冲上限。
  • maxDepth(默认 100):嵌套深度上限。

超限会抛出错误并由渲染器降级处理,不会崩溃整页。