web页面渲染(二)
作者:小辞 标签:网站优化

客户端渲染(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

 

服务器端渲染在过去几年拥有大量的开发者。

 

流服务器渲染允许你以块的方式发送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/web/updates/2019/02/rendering-on-the-web