18.1 CSR、SSR 以及同构渲染
Vue.js 既支持客户端渲染(CSR)与服务端渲染(SSR),也能把两者结合成同构渲染;先弄清三者的流程与取舍,才能理解后面为什么要在服务端产出 HTML 字符串、又要在客户端做激活。
一、CSR:全部在浏览器里完成
客户端渲染(client-side rendering,CSR) 在浏览器中完成模板与数据的融合,再渲染出最终的 HTML 页面。
- 客户端向服务器或 CDN 请求静态的 HTML 页面;
- 浏览器加载 HTML 中引用的资源(CSS / JavaScript);
- 服务器或 CDN 把资源返回给浏览器;
- 浏览器解释并执行 CSS 与 JavaScript,执行完成后才渲染出页面内容,在此之前页面一片空白,即白屏;
- 客户端再通过 AJAX 请求 API 获取数据,拿到数据后完成动态内容渲染,呈现完整页面。
之后用户点击「跳转」并不会真正刷新页面,而是由前端路由动态渲染出新页面。
二、SSR:模板与数据在服务端融合
服务端渲染(server-side rendering,SSR) 的工作流程:
- 用户通过浏览器请求站点;
- 服务器请求 API 获取数据;
- 接口把数据返回给服务器;
- 服务器根据模板和获取到的数据拼接出最终的 HTML 字符串;
- 服务器把 HTML 字符串发送给浏览器,浏览器解析并渲染。
用户再次通过超链接跳转时,上述 5 步会完整地重新走一遍。
三、CSR 与 SSR 的对比
| 维度 | CSR | SSR |
|---|---|---|
| SEO | 不友好(首屏 HTML 是空壳) | 友好(HTML 里已有内容) |
| 首屏时间 / 白屏 | 有白屏,内容到达时间更晚 | 内容到达更快,无白屏 |
| 服务器压力 | 渲染在客户端,占用少 | 每次渲染都在服务端,占用多 |
| 页面跳转体验 | 前端路由,无需真正跳转,更流畅 | 每次跳转都要服务端重新渲染 |
四、同构渲染(isomorphic rendering)
「同构」一词的含义是:同一套代码既可以在服务端运行,也可以在客户端运行。同构渲染分为两种场景:
- 首次渲染(首次访问或刷新页面):流程与 SSR 完全一致;
- 非首次渲染(页面内跳转):与 CSR 一致,由前端路由动态渲染。
同构渲染产出的 HTML 与纯 SSR 有一处最大的不同:它包含当前页面所需的初始化数据。服务端请求到的数据会被序列化为字符串,拼接进静态 HTML 中一并发送给浏览器,客户端因此无需再次请求接口。
激活(hydration)
浏览器拿到静态 HTML 后会立刻展示(所以没有白屏),但此时页面不可交互,还需要客户端激活。激活包含两部分工作:
- 在当前已渲染的真实 DOM 元素与 Vue.js 组件渲染出的虚拟 DOM 之间建立联系;
- 从 HTML 页面中提取服务端序列化后发送过来的数据,用以初始化整个 Vue.js 应用。
激活完成后,整个应用已经完全被 Vue.js 接管为 CSR 应用,后续操作都按 CSR 流程执行;一旦刷新页面,会重新走「服务端渲染 → 激活」,如此往复。
两个常见误解
同构渲染并不能提升可交互时间(TTI)。它仍然要像 CSR 那样等待 JavaScript 资源加载完成,并且等客户端激活完成后才能响应用户操作。
同构渲染在首次渲染与刷新时仍由服务端完成渲染,因此仍占用部分服务端资源,只是比「所有页面跳转都在服务端渲染」要轻。
相关
- 18.2 将虚拟 DOM 渲染为 HTML 字符串:同构渲染在服务端的第一步,把 vnode 拼接成 HTML 字符串