目录
1. 实际业务的困境
现有的服务端渲染(Server-side rendering,简称 SSR)的原理是当 HTML 请求到达 Node 端时先等待后端接口数据请求完成(30~300ms),然后再进行渲染(2~5ms),最后再响应渲染完成的页面给浏览器。
大致流程是: fetch data (server) → render to HTML (server) → load code (client) → hydrate (client)
如本文用作示例的商品管理
页面,需要并发8个后端接口请求,最慢的接口 /api/xxx/goodsList
延时为 246.6 ms,导致Step1阶段
用户看到的页面白屏时间至少是 246.6ms + 5ms。
💡 Step2 截图为灰色仅为了区别于 Step3 可交互状态,实际用户看到的效果与 Step3 无差异
为了解决后端接口延时不可控造成的 Step1 阶段白屏时间过长的问题,于是我们开发了渐进式渲染
功能,优化后的渲染链路变成了如下
2. Suspense SSR 架构
React18 新的 Suspense SSR 架构允许你在服务端使用 Suspense
组件,比如你的 Comments
组件是需要后端接口的数据,那么可以做到后端接口数据仅阻塞 Comments
组件,不会阻塞整个 App
组件的渲染与提前返回
1 | <Layout> |
新 Suspense SSR 架构下的渲染链路变成了如下
2.1. 可能存在的问题
你可能想到部分可交互状态时,如果客户端其他组件响应了事件导致 Comment
组件的 props 变化,而服务端是根据 initProps 对 Comment
进行的渲染,那么 React 会如何取舍
1 | function Content() { |
从测试结果来看 Props 发生变化后 React 会以客户端最新渲染的结果为准, 与此同时抛出Uncaught Error: This Suspense boundary received an update before it finished hydrating.
错误
3. 应用到业务中的效果
因为 Suspense 支持对于单个组件进行的延迟渲染,首先我们需要对页面组件进行拆分,同时使用 Suspense 进行包裹
如果升级到了新 Suspense SSR 架构下的渲染链路变成了如下
4. 小结
Suspense SSR 架构解决了服务端渲染各个流程串行等待问题,强调一切按需(懒加载,懒编译,现在是懒渲染?)进行
- 渐进式渲染像是 React 原生不支持 Suspense SSR 下的模拟实现
渐进式渲染首屏比 Suspense SSR 更加完整
- 渐进式渲染: 服务端渲染时虽然没有接口数据,但根据 initState 能够渲染出较完整的首屏
- Suspense SSR: 需要接口数据的组件首屏都是渲染的占位组件,如 Spinner
Suspense SSR 类似于懒渲染,设计理念更加符合现代化 Web 开发
5. 最后的话
如果发现升级后页面没有进行分块渲染, 或许你要继续阅读 👉 服务端流式渲染 iOS 中踩坑记