“流式拼接”指利用 readablestream 动态、渐进式生成 html 响应,按需写入语义完整 html 片段,实现浏览器边接收边解析渲染,提升首字节速度、降低内存占用并增强容错性。

识别“流在 Service Worker 拼接模板中的高阶妙用:实时合成页面”,关键不在于找一个叫“流”的新 API,而在于理解 ReadableStream 如何被用于动态、渐进式地生成 HTML 响应——这才是“实时合成页面”的技术内核。
什么是“流式拼接”而非字符串拼接
传统动态响应多用字符串模板(如html`${header}${main}${footer}`),一次性构造完整 HTML 字符串再返回。而“流式拼接”是指:
- 不等待所有区块加载完成,而是按需读取并立即写入响应流
- 利用
new Response(new ReadableStream({...}), {...})构造可流式传输的响应 - 浏览器收到响应后边接收边解析渲染,实现首字节更快、内容逐步浮现的效果
典型场景:个性化首页的流式合成
例如用户访问 /home?lang=zh&theme=dark,Service Worker 可:
- 先从缓存快速读取已就绪的
header_zh_dark,立刻推入流 - 同时异步读取
featured_promo_v2(可能来自 IndexedDB)和user_welcome_123(需查用户偏好) - 任一模块就绪即写入流,无需等全部完成;footer 最后写入并关闭流
- 整个过程浏览器持续接收 HTML 片段,导航体验更接近 SSR 流式渲染
实现要点:避免阻塞,控制 chunk 粒度
流式合成不是“越碎越好”,需平衡网络效率与渲染节奏:
- 每个写入 chunk 应为语义完整片段(如一个
<section></section>或带闭合标签的组件) - 避免在流中写入未闭合的 HTML 标签,否则浏览器解析会挂起或出错
- 使用
controller.enqueue(new TextEncoder().encode(htmlChunk))推送 UTF-8 字节 - 务必设置
Content-Type: text/html; charset=utf-8,否则流可能被误判为下载
与“非流式动态拼装”的本质区别
两者都支持按需组合区块,但流式带来三重升级:
- 感知延迟更低:header 渲染快于整个页面生成耗时
- 内存更友好:无需在内存中暂存数 KB 的完整 HTML 字符串
- 失败更可控:某区块加载失败可降级为空白或占位符,不影响其余流输出










