后端与接口
需要更快 TTFB/FCP 时用 React 流式 SSR…
在 React 服务端渲染中,把 HTML 外壳先发给客户端、慢内容后续流式发送,以降低 TTFB、FP、FCP 并改善背压。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
需要更快 TTFB/FCP 时用 Rea特定
解决思路
- 在 React 18+ 中,用 renderToPipeableStream 替代已废弃的 renderToNodeStream;Node.js HTTP 响应用 renderToPipeableStream,Web Streams/边缘运行时用 renderToReadableStream。
- 把流式 SSR 与 React Suspense 边界结合:慢速部分放进 Suspense,让外壳和快内容先流出,慢内容准备好后再流式发送。
- 调用 renderToPipeableStream(<App />, options) 时在 options 中设置 bootstrapScripts: ["/build/client.js"],让客户端 hydration 脚本随流式 HTML 正确加载。
- 使用 onShellReady 回调:一旦关键外壳准备好,就立即开始向客户端流式输出。
- 在 onShellReady 中设置 response.statusCode = didError ? 500 : 200,设置 response.setHeader("Content-Type", "text/html"),然后调用 pipe(response)。
- 使用 onError 回调处理流式渲染错误:设置 didError = true,并执行 console.error(error)。
- 在请求处理函数中维护 didError 标志,使 onError 捕获错误后 onShellReady 能返回 500 状态码。
- 返回的初始 HTML 外壳应包含 DOCTYPE、<head>(title、stylesheet、type="module" defer 的 /build/client.js 等)以及 <body> 中的 approot 容器。
- 客户端使用 hydrateRoot() 对服务端流式返回的 HTML 进行 hydration,实现渐进式 hydration。
- 不要像 renderToString 那样等整个组件树渲染完再发送响应;流式方案应在服务器生成 chunk 时逐步发送 HTML 字节,先 flush 外壳,再发送较慢内容。
- 利用流式对网络背压的响应:网络拥塞、无法继续传输字节时,渲染器会收到信号并暂停流式发送,网络恢复后继续;这能减少服务器内存占用并提高 I/O 响应性。
- 依赖流式让 Node.js 服务器同时处理多个请求,避免较重的请求长时间阻塞较轻的请求,从而在困难网络条件下保持站点响应。
- 从 renderToString 迁移到流式时,不要做简单查找替换;先识别并处理依赖字符串输出、需要在前置标记中生成内容、或用 renderToStaticMarkup 包裹 renderToString 的代码。
适用边界 · 注意事项
- 托管环境不支持流式响应(某些 serverless 平台会缓冲完整响应),或中间件/反向代理会缓冲响应,导致流式收益消失。
- 简单静态页面且 HTML 很小,流式不会带来有意义的性能提升。
- 不能简单替换 renderToString 的场景:框架依赖 server-render-pass 先生成必须放在 SSR chunk 之前的标记(如动态决定 CSS 并写入前面的 <style>),或使用 renderToStaticMarkup 生成页面模板并在其中嵌入 renderToString 动态内容(这些代码预期得到字符串而非流)。