Streaming SSR 与 Suspense 粒度

cacheComponents 下的真实流式渲染:静态壳构建期预渲染先行吐出,三个不同时延的异步区块作为动态洞各自包 Suspense 分段到达;边界粒度决定谁阻塞谁

分段到达的三个区块

刷新页面观察:页头与骨架立即出现,三个区块按 0.5s / 1.5s / 3s 依次补出

快数据(0.5s)

等待数据中…

中速数据(1.5s)

等待数据中…

慢数据(3s)

等待数据中…

谁阻塞谁

Suspense 边界的粒度,决定了慢数据的爆炸半径

  • 没有 Suspense 时:页面里最慢的那个 await 决定整页 TTFB,3s 的慢查询会让 0.5s 的快数据一起白屏等待
  • 有了边界:静态壳(标题、导航、骨架)先流出去,浏览器立刻可渲染; 每个慢区块在自己的边界内独立 resolve,分段补出、互不相干
  • 本页无需任何路由级配置:cacheComponents 下,Suspense 边界内 未缓存的 async 组件自动成为请求时渲染的动态洞,壳在构建期预渲染 —— build 输出里本页标为 ◐(Partial Prerender)。 旧模型(Next 15 及以前)要靠薄壳导出dynamic = "force-dynamic"整页退出静态化,否则构建期拍平成静态 HTML,看不到流式效果
  • dev 下观察方式:刷新页面看内容分段出现;或用curl -N抓响应体,能看到 HTML 分 chunk 到达、尾部带着补洞的$RC脚本

什么时候别用 Streaming

决策要点,而非 API 背诵

  • SEO 关键内容不要放进 Suspense 洞:爬虫对分段补出的内容收录不稳定,正文/标题必须随壳一起吐出
  • 所有数据都很快(几十毫秒内)时,边界是多余的复杂度:壳与洞几乎同时到达,反而多一次渲染调度
  • 数据间有强依赖(后一个查询要等前一个的结果)时,边界解决不了瀑布,先消依赖再谈分段