共计 3033 个字符,预计需要花费 8 分钟才能阅读完成。
客户端渲染(CSR)
客户端渲染意味着在浏览器中使用 Javascript 直接渲染页面。所有的逻辑,数据获取,模板和路由都在客户端处理。
对于移动设备来说,客户端渲染很难得到或者保持一种快速的访问水平。如果它做最少的工作,保持严格的 Javascript 预算,并尽可能减少数据请求往返的时间,那么它可以接近纯服务器端渲染的性能。使用 HTTP/ 2 推送或者是 <link rel=preload> 可以使得关键脚本和数据得以更快的传递, 从而使得解析器更快的为你工作。为了确保初始化和随后的导航感觉立刻就能完成,像 PRPL 这样的模式就比较值得去做。
客户端渲染主要的缺点就是 Javascript 的数量会随着应用程序的增长而变得越来越多。当有额外的新 Javascript 类库,polyfills 和第三方代码的时候,优化工作会尤其困难。然而这些代码也会竞争系统的处理能力,因此在页面内容被渲染完成之前,必须要经常处理一些东西。
对于构建单页应用的人员来说,对于被大多数页面共享的核心用户接口,你可以尝试应用 Application Shell 缓存技术。并与 service workers 相结合,它可以明显提高重复访问的时候的感知性能。
通过 rehydration 合并服务器端渲染和客户端渲染
这种方式通常被称为“Universal Rendering”或简称为“SSR”,这种方式试图通过平滑的方式来平衡客户端渲染和服务器端渲染。诸如全页加载或者是重新加载的请求会在服务器端被处理,在服务器端会把其转为 HTML,然后 Javascript 和渲染所用到的数据会被一起插入到最后的结果页面。如果实现的好的话,这种方式会像服务器端渲染那样产生一个很快的 First Contentful Paint。服务器端返回结果以后,会在客户端会通过一个叫(rehydration)的技术再次渲染。这是一个比较新的解决方案,但是他可能有比较大的性能缺陷。
rehydration 的 SSR 的主要的缺点就是它对 Time To Interactive 有着明显的缺点,即使它会提高 First Paint。它经常看起来是具有欺骗性的加载和交互,因为它实际上在 js 以及事件处理完成之前,是无法响应输入的。在手机端可能会花费数秒钟才会让页面真正可以使用。
你可能经历过以下问题 – 页面请求加载一段时间以后,你的网页看起来已经加载好了,但是点击以后什么都不会做,你可能很快就会变得崩溃 …“现在到底发生什么事情了?为什么我不能滚动页面”。
一个 Rehydration 的问题:一个应用程序要构建两次
由于 JS 的原因,Rehydration 的问题通常要比延迟可用的问题要更糟。为了使客户端的 Javascript 能够精确的“获取”服务器停止渲染的位置,而不必重新渲染服务器已渲染过的 HTML,当前的 SSR 解决方案通常会序列化其 UI 响应,并把其依赖的数据作为标签放进文档中。HTML 文档的结果包含一个更高级别的重复。
正如你所看到的,在响应中服务器不仅返回一个应用程序 UI 的描述给浏览器,而且还吧相关的数据也一并返回了过来,当启动客户端的时候,UI 会再次实现渲染一次。其只在 bundle.js 已经完成加载和解析以后,UI 才会变为可交互的。
在真实世界中通过使用 SSR 来收集性能指标,其结果通常会比较令人沮丧。原因归结于用户体验:它很容易使用户留在一个“不可思议的山谷中”。
虽然 SSR 有 rehydration 的希望。但是是在一个很短的时期内,在更高的可缓存的内容中使用 SSR 可以减少 TTFB 延迟。产生一个和预渲染相似的结果。递增的,逐步的,部分的 rehydration 可能是未来技术可用性更高的关键 (Rehydrating incrementally, progressively, or partially may be the key to making this technique more viable in the future)。
流服务器渲染和渐进式 Rehydration
服务器端渲染在过去几年拥有大量的开发者。
流服务器渲染允许你以块的方式发送 HTML,浏览器可以通过接收到的片段进行渐进式的渲染。由于内容可以更快的送达给用户,所以他可以带来更快的 First Paint 和 First Contentful Paint。在 React 中,流通过 renderToNodeStream() 被异步传输 – 相比于同步渲染方式 – 意味着背压处理效果会更好。
渐进式 rehydration 也是值得一看的,在一些 React 已经对此有了一些相关的探索了。通过这种方法,服务器端渲染的每一个部分内容都会随着时间的推移而启动,而不是目前通用的方法,通过一次初始化整个应用程序。这可以帮助我们减少页面交互所需要的 Javascript 的代码量。因为可以延缓低优先级客户端的内容过早的执行,以使得防止阻塞主线程的执行。它还可以帮助避免最常见的 SSR Rehydration 陷阱之一,其中服务器呈现的 DOM 树被破坏然后立即重建 – 通常是因为初始同步客户端渲染所需的数据还没有完全准备好,可能还在等待 Promise 解析的完成。
部分 Rehydration
部分 Rehydration 已经被证明是难以实现的。这种方法是渐进式 rehydration 的一种扩展。其中逐步分析了渐进式的 rehydration 的每一个部分。标记了那些交互性很小,或者没有交互性的那些。对于每个几乎静态的部分,对应的 Javascript 会被转换为惰性引用或者是装饰函数中。将其客户端占用空间减少到接近为零. 部分 Rehydration 也会有自己的问题和妥协。它为缓存带来了一些有趣的挑战,而客户端导航意味着我们无法假设应用程序的惰性部分的服务器呈现的 HTML 将在没有完整页面加载的情况下可用。
Trisomorphic 渲染
如果 service workers 对于你来说是一个选项的话。那么对于“trisomorphic”渲染来说,你可能也是感兴趣的。这是一种可以将初始 / 非 JS 应用在流服务器上的一种技术,然后让您的服务工作者在安装后渲染为 HTML 以进行导航,这可以使缓存的组件和模板保持最新,并启用 SPA 样式导航以在同一会话中呈现新视图。当您可以在服务器,客户端页面和服务器工作程序之间共享相同的模板和路由代码时,此方法最有效。
SEO 注意事项
当在网站上选择渲染策略时,团队通常会考虑 SEO 的影响。服务器端渲染通常被选择提供一个对于爬虫“完全可视”的,更容易爬取的网页。爬虫可能会理解 Javascript,但是他们在渲染中通常有值得注意的限制。客户端渲染可以工作,但是通常没有额外的测试工作。最近的动态渲染逐渐成为一个值得考虑的选项,如果你的架构很大部分都是由客户端 Javascript 驱动的话。
如果有疑问,移动友好测试工具对于测试您选择的方法是否符合您的预期非常宝贵。它显示了 Google 抓取工具显示任何页面的方式预览,找到的序列化 HTML 内容(执行 JavaScript 后)以及渲染过程中遇到的任何错误。
总结
当决定渲染的方法的时候,首先要测量并且理解你的瓶颈是什么。思考静态渲染或者是服务器端渲染是否可以满足你 90% 的需求。用最少的 JS 发布 HTML 也是极好的,其会得到一个可交互的用户体验。下面是一个方便的信息图,显示了服务器 - 客户端频谱。
本文翻译自:
https://developers.google.com…
本文转载自 http://www.lht.ren/article/14/