SSR 、CSR、预渲染、同构等首屏优化技术要如何选择?

作为开发者,你可能经常会面对这样一件事情,需要你做出影响整个应用架构的决策,而web开发者的核心决策之一就是应用逻辑渲染工作的实现,判断渲染工作应该处于架构中的什么位置,是客户端还是服务器呢?由于现在有很多不同构建网站的方法,因此这些决策变得更加困难,为了更好地理解在做出决定时所选择的架构,我们需要对每种方法有充分的理解,并且在谈到它们时能够有一致的术语,关于对术语的理解,我们可以先来看看与渲染有关的词:

  • SSR: 指的是服务器渲染(Server-Side-Rendering),也就是在服务器上将客户端或者通用(universal)应用程序渲染成HTML。
  • CSR: 说的是客户端渲染(Client-Side-Rendering)也就是在浏览器中渲染APP,通常使用DOM。
  • Prerender:说的是预渲染(Prerendering),也就是说在构建时运行客户端应用程序,这样将它的初始状态捕获为静态HTML。
  • Isomorphism:说的是同构(Isomorphism),是指服务器端渲染(SSR)时或者Native渲染时复用浏览器端的javascript组件。

性能相关的术语:

  • TTFB:首字节时间(Time To Firt Bype)也就是从点击链接到接收第一个字节内容之间的时间。
  • FP: 首次绘制(First paint)也就是第一次有像素对用户可见的时间。
  • FCP:首次内容绘制(First Contentful Paint)也就是请求内容变得可见的时间。
  • TTI: 可交互时间(Time To Interactive)主要指的是页面变为可交互的时间(事件绑定等)。

那么针对SSR,CSR,预渲染,同构等首屏优化技术,你要如何进行选择呢,接下来该如何解决这个问题呢?

先来看看服务器渲染

服务器渲染指在服务器中生成整个页面的HTML,以此响应请求的技术。避免了在客户端上进行数额外据获取的往返(round-trips)和模板处理。因为这些工作在浏览器获得响应之前已由服务处理了。

服务渲染通常会得到快速的首次绘制和首次内容绘制,在服务器上运行页面逻辑和渲染。可以避免向客户端发送大量Javascript,也有助于实现快速的可交互时间TTI,这方法之所以运行的通,是因为服务器渲染的本质只是向用户浏览器发送文本和链接,可以看出这种方法是适用于广泛的设备和网络的,并且能够触发一些有趣的浏览器优化。比如流文档解析。

使用服务器渲染,用户不再需要在客户端上等待CPU相关的Javascript处理后,然后才能访问站点,即使第三方JS无法避免,使用服务器渲染来减少自己的JS成本,也能提供更多的性能预算。但是这种方法有一个主要的缺点,那就是在服务器上生成页面有一定的耗时,可能会导致较慢的首字节时间TTFB,其实服务器渲染是否满足应用程序,很大程度上取决于构建目标的体验类型。关于服务器渲染和客户端渲染的正确应用,存在长期的争论,但重要的是我们可以选择对某些页面使用服务器渲染,而对于其余页面不使用。

一些网站已经成功采用混合渲染技术,Netflix服务器渲染相对于静态的落地页面,同时为交互繁重的页面预拉去JS,为这些重客户端页面提供更快的加载能力,许多现代框架,库,架构使得在客户端和服务器上渲染相同的应用程序成为可能,这些技术可以用于服务器渲染,但是要注意,在服务器和客户端进行渲染的架构都是各框架自家的解决方案具有不同的性能特点和权衡

  • React用户可以使用renderToString(), 或者在它上上面构建的解决方案,比如Next.js用于服务器渲染。
  • Vue用户可以查看Vue的服务器渲染指南 或者 Nuxt。
  • Angular有Universal。

 由于大部分流行的解决方案采用某种Hydration的形态,因此在选择工具之前要注意使用的方法。

 

 

 

静态渲染(StaticRendering)

静态渲染在构建时进行,并提供快速的FP,FCP和TTI。

也就是假设客户端JS的体积得当,不过与服务器渲染不同,它还致力于实现始终如一的快速首字节时间,因为页面的HTMl不必动态生成,通常情况下,静态渲染意味着提前为每个URL生成单独的HTML文件,通过预生成HTML响应,可以将静态渲染部分部署到多个CDN来利用边缘缓存,也就是页面静态化,页面静态化方案选择很多,像Gatsby这样的工具,目的就是在于让开发人员感觉它们的应用程序是动态渲染的,而不是构建过程中生成的,JekylMetalsmith(静态)提供更多的模板启动的方法,更加符合它们的静态特质。

静态渲染的缺点:必须为每个可能的URL生成单独的HTML文件。如果无法提前预测这些URL的内容,或者对于具有大量不同页面的网站,这可能具有挑战性,甚至是不可行的。

对于react用户而言,可能比较成熟的Gatsby,Next.js静态导出 或 Navi,它们都可以方便使用组件,但是了解静态渲染和预渲染之间的区别也非常重要。

静态渲染页面是无需执行太多客户端JS就可以交互的,而预渲染也改进了单页面的FP或FCP。由于单页面应用,因此必须等待客户端启动过程,通过这样来使页面真正具有可交互性,不过如果你不确定是选择静态渲染还是预渲染方案,我建议你可以尝试下这个测试:

禁用Javascript并加载创建的网页,对于静态页面渲染的页面而言,大多数功能在没启用Javascript下仍然可以正常运作,而对于预渲染页面来说,一些基本的功能,比如链接能正常展现,但其余部分无法正常展现。

还有一个有效的测试就是使用ChromeDevTools减慢网络速度,并观察在页面变为可交互之前,已经下载了多少Javascript,预渲染通常需要更多的JavaScript来实现交互,并且这些JS往往比静态渲染使用的渐进增强方法更加复杂。

不过服务器渲染并不是银弹,因为它的动态特性也带来了显著的计算成本,许多服务器渲染解决方案会有耗时,导致延迟的TTFB或者成倍的数据传输,在React中renderToString可能很慢,因为它是同步和单线程的。

 

客户端渲染(Client Side Rendering)

客户端渲染意味着使用Javascript直接在浏览器中渲染页面,所有的逻辑、数据获取、模板、路由都在客户端处理,而不是在服务器上。

客户端渲染时很难在移动端做到很快的,如果做好压缩工作,严格控制Javascript的预算,并在尽可能少的RTT中提供内容,它可以接近纯服务器渲染的性能,使用HTTP2 ServerPush或者<link rel=reload>可以更快的提供关键脚本和数据,这将使解析器更快地完成工作,像PRPL这样的模式值得评估,通过这样来确保初始和后续导航时的即时感。

那么客户端渲染的主要缺点是什么呢?随着应用程序的发展,所需的Javascript数量会增加,随着添加新的Javascript库,polyfill和第三方代码,更是一发不可收拾,这些代码会竞争处理能力,并且通常必须在渲染页面内容之前完成处理,构建依赖大型Javascript的CSR应使用时,应该考虑积极的代码分割,并确保延迟加载Javascript,对于很少或没有交互性的页面来说,服务器渲染可以作为更具有扩展性的解决方案。

 

通用渲染

通过Rehydration将服务器渲染和CSR相结合的这种方法,它通常被称为通用性渲染。或者简称SSR

它试图通过两者兼顾来来平滑客户端渲染和服务器渲染之前的权衡,页面请求交由服务器处理,将应用程序渲染为HTML,然后把用于渲染的Javascript和数据,嵌入到生成的文档中,只要处理得当,这就像服务器渲染一样实现了快捷的FCP,然后通过称为(Re)hydration的技术,在客户端上再次拾取来渲染,这是一种新颖的解决方案,但也具有一些明显的性能缺陷,那么Rehydration后的SSR主要的缺点是什么呢?

主要就在于它会对可交互时间产生显著的负面影响,即使它改善了首次绘制,SSR页面通常看起来具有欺骗性的加载完成和可交互性,但在执行客户端js并绑定事件处理之前,页面实际上无法响应输入,这在移动设备上可能持续几秒甚至几分钟,也许你自己也经历过这种情况,在页面看起来已经加载后的一段时间内,点击或触摸什么都没反应,这很快变得令人沮丧,同时也伴随着一些疑问,为什么没有反应,为什么我不能滚动,由于js特性,Rehydration问题往往比延迟交互更糟糕,一个Rehydration问题可能存在应用的双重成本问题

为了使客户端Javascript不需要再次重新请求服务器,就能准确地获取到服务器返回的用于呈现其HTML时的所有数据,当前的SSR解决方案是通常将UI的数据响应序列化,以Script标签形式存放在HTML中。

结果是生成的HTML文档包含大量重复片段,正像你所看到的服务器除了返回应用程序UI来响应页面请求,还返回了用于组成该UI的源数据,以及生成相同UI的实现代码,立即在客户端上显示,只有在bundle.js完成加载和执行后页面才会变得可交互,从使用Rehydration SSR站点收集的性能数据显示,这种用法应该极力避开使用,归根结底,原因在于用户体验上,这很容易让用户处于不明所以的状态。

不够RehydrationSSR也不是没有希望,在短期内,只将SSR用于高度可缓存的内容,可以减少TTFB延迟,从而达到预渲染类似的效果。

 

三方同构渲染 TrisomorphicRendering

如果可以使用serviceworker,Trisomorphic渲染也是很有意思的,这个技术是指利用流式服务器渲染初始页面。

等ServiceWorker加载后,接管HTML的渲染工作,是可以利用缓存的组件和模板保持最新,并启用SPA式的导航来保证在同一会话中渲染新视图,当可以在服务器、客户端页面以及ServiceWorker之间共享相同模板和路由时这个方法最有效。

 

那么在选择渲染策略时,都需要考虑哪些呢,其实不少团队会考虑对SEO的影响,为了让爬虫能够轻松获得完整页面,我认为服务器渲染时不二的选择,虽然爬虫可能会理解Javascript,但是在渲染方式上的局限性上也需要注意,如果你的应用非常注重Javascript,最近的动态渲染解决方案也是一个值得考虑的选择。如果有疑问?

Mobile-FriendlyTest工具,对于测试你选择的方法是否符合预期,是非常有用的,它展示了Google爬虫渲染页面的预览,执行Javascript的后序列化的HTML内容,以及渲染过程中发生的错误。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值