首页 男生 其他 深入浅出React和Redux

12.1 服务器端渲染vs浏览器端渲染

深入浅出React和Redux 程墨 5269 2021-04-06 02:29

  您可以在百度里搜索“深入浅出React和Redux 艾草文学(www.321553.xyz)”查找最新章节!

  

  12.1 服务器端渲染vs浏览器端渲染

  我们首先回顾一下万维网的历史,万维网技术是从服务器端渲染发展起来。最初,所有的网页都是静态网页,服务器上存储的只有一些静态HTML文件,浏览器通过HTTP协议访问到的就是这些静态HTML。这样虽然可以建立纯文档的万维网,但是没法提供动态内容,这无法满足利用网页制作动态内容应用的需要。

  随后,CGI技术出现,服务器端终于可以产生动态内容的HTML了,这是一个巨大的进步,给了互联网无限的可能性。因为需求存在,所以服务器端各种语言、各种框架层出不穷,JSP、ASP、PHP、Ruby on Rails、Python……可以列出一个超长的技术名单,所有这些技术做到的都是“服务器端渲染”,也就是对于来自浏览器的HTTP请求,服务器通过访问存储器或者访问别的API服务之类的方式获得数据,然后根据数据渲染产生HTML返回给浏览器,浏览器只要把HTML渲染出来,就是用户想要看的结果。

  服务器渲染方式统治了网页应用开发很长时间,到现在也依然有很大影响力,但是,用户对网页应用的要求也越来越高,传统的服务器渲染对于每个HTTP请求都要产生一份全新的HTML,这样每个HTTP请求都保持独立,这种方式当然有利于功能扩展,但是一个缺陷就是会有浪费。毕竟很多网页切换只需要一个局部的更新,却依然要网页重新下载刷新,体验会有一点差。而用户希望更好的体验,于是就有了AJAX,可以在不刷新网页的情况下通过局部更新提高用户体验,随AJAX而来的就是Web2.0的浪潮。

  技术没有止步于AJAX,最初使用AJAX的应用大多依然通过服务器渲染产生一个包含可渲染内容的HTML网页,只有局部的更新使用AJAX完成,于是,有的开发者已经开始思考,是不是可以干脆不用服务器端返回有内容的HTML,是不是可以让应用功能完全用JavaScript在浏览器端产生HTML呢?

  2009年,Twitter网站就进行过这样的尝试,服务器返回的HTML只包含几个无内容的元素作为页面框架,但是,网页中引用的JavaScript文件会直接访问API服务器来获取数据,获取的数据再通过模板库产生HTML字符串,把HTML字符串插入到页面框架中,就产生了用户最终看到的界面,这就是“浏览器端渲染”的方式。

  反思当年Twitter的尝试,并不算十分成功,因为模板库的效率并不是很高,加上用户需要等待API请求成功之后才能看到第一条有意义内容。所以非但没有提高用户体验,反而让用户感觉更慢了,最终Twitter放弃了这种纯靠浏览器渲染的方式,直到今天,Twitter网站依然是服务器端渲染配合浏览器端渲染的工作方式。

  不过,整个行业并没有被这点挫折吓倒,更多的支持完全“浏览器端渲染”的方案提了出来。

  传统上,一个浏览器端渲染的方案,一般要包含这几个部分:

  ·一个应用框架,包含路由和应用结构功能,例如Backbone.js就是这样的MVC框架,当然Redux这样遵循单向数据流的框架配合React-Router也可以胜任;

  ·一个模板库,比如mustache,通过模板库开发者可以定义模板,模板以数据为输入,输出的就是HTML字符串,可以插入到网页之中,React可以替换模板库的功能;

  ·服务器端的API支持,因为应用代码完全部署在页面的JavaScript中,获取数据不能像服务器端渲染那样有直接访问数据库的选择,只能要求有一个提供数据的API服务器,通常就是一个RESTful API。

  传统的模板库就是生硬的字符串替换操作,无论如何优化都会有它的极限,而且模板的输出依然是字符串,将HTML字符串插入网页的过程,也就是DOM树的操作,性能也无法优化。在前面的章节中我们介绍过React的Virtual DOM工作原理,配合生命周期函数的应用,性能不是字符串替换的模板库能够比拟的。

  React可以将网页内容(HTML)、动态行为(JavasScript)和样式(CSS)全部封装在一个组件中,把浏览器端渲染的应用发挥到了极致。

  虽然完全的浏览器端渲染很有市场,但是这种方式有一个难以摆脱的阴影,那就是首页性能。

  为了便于量化网页性能,我们定义两个指标:

  ·TTFP(Time To First Paint):指的是从网页HTTP请求发出,到用户可以看到第一个有意义的内容渲染出来的时间差;

  ·TTI(Time To Interactive):指的是从网页HTTP请求发出,到用户可以对网页内容进行交互的时间。

  TTFP这个时间差当然越短越好,也就是说应用要尽早显示有意义的内容给用户,不要让用户只对着一个空白屏幕发呆;TTI肯定要比TTFP要长一些,因为没有内容哪里会有交互,当渲染出内容之后,还要JavaScript代码给DOM元素添加事件处理函数才会有交互结果,这个过程需要一些时间。

  在一个完全靠浏览器渲染的应用中,当用户在浏览器中打开一个页面的时候,最坏情况下没有任何缓存,需要等待三个HTTP请求才能到达TTFP的时间点:

  ·向服务器获取HTML,虽然这个HTML只是一个无内容的空架子,但是皮之不存毛将焉附,这个HTML就是皮,在其中运行的JavaScript就是毛,所以这个请求是不可省略的;

  ·获取JavaScript文件,大部分情况下,如果这是浏览器第二次访问这个网站,就可以直接读取缓存,不会发出真正的HTTP请求;

  ·访问API服务器获取数据,得到的数据将由JavaScript加工产生之后用来填充DOM树,如果应用的是React,那就是通过修改组件的状态或者属性来驱动渲染。

  总共有三个HTTP请求,在三个不可预料的网络请求之后,才可以渲染第一个有意义内容,即使第二个HTTP请求利用了缓存,那也需要两个HTTP来回的时间。

  提示

  实际上,按照Progressive Web App的规格,可以通过Manifest和Service Worker技术进一步优化,避免第一个获取HTML的请求和第三个访问API的请求,但是这种技术超出了本书讨论的范围,而且这些技术也并不适用于所有网页应用,在这里只讨论一般情况。

  对于一个服务器端渲染,因为获取HTTP请求就会返回有内容的HTML,所以在一个HTTP的周期之后就会提供给浏览器有意义的内容,所以首次渲染时间TTFP会优于完全依赖于浏览器端渲染的页面。

  注意

  除了更短的TTFP,服务器端渲染还有一个好处就是利于搜索引擎优化,虽然某些搜索引擎已经能够索引浏览器端渲染的网页,但是毕竟不是所有搜索引擎都能做到这一点,让搜索引擎能够索引到应用页面的最直接方法就是提供完整HTML。

  上面的性能对比当然只是理论上的分析,实际中,采用服务器端是否获得更好的TTFP有多方面因素。

  首先,服务器端获取数据快还是浏览器端获取数据块?虽然服务器端渲染减少了一个浏览器和服务器之间的HTTP访问周期,也就是获取数据的过程,但是在网页服务器上一样有获取数据的过程,如果在网页服务器上访问数据存储或者API服务器的延时要比从浏览器端更短,那么才能体现服务器端渲染的优势。当然,大多数情况下,在网页服务器上获取数据的确更快,开发者只需要确认这一点就行。

  其次,服务器端产生的HTML过大是否会影响性能?因为服务器渲染让网页服务器返回包含内容的HTML,那样首页下载的HTML要比纯浏览器端渲染要大,这样下载HTML的时间也会增长,这样导致服务器渲染未必能获得更好的性能。特定于React应用,服务器端渲染需要在网页中包含“脱水数据”,除了HTML之外还要包含输入给React重新绘制的数据,这样导致页面的大小比最传统的服务器端渲染产生的页面还要大,更要考虑页面大小对性能的影响。

  最后,服务器端渲染的运算消耗是否是服务器能够承担得起的?在浏览器渲染的方案下,服务器只提供静态资源,无论HTML还是JavaScript,提供静态资源对服务器压力较小,甚至可以交给CDN来承担,这样服务器基本无压力,产生网页HTML的运算压力被分摊到了访问用户的浏览器中;如果使用服务器端渲染,那么页面请求都要产生HTML页面,这样服务器的运算压力也就增大了。对应React,使用服务器端渲染可能对服务器的运算压力很大,因为Facebook已经明确说React并不是给服务器端渲染设计的,Facebook本身也没有在实际产品中应用React的服务器端渲染。

  总结一下,我们既列举了服务器端渲染优点,也分析了服务器端渲染潜在的风险。那么,应不应该使用React服务器端渲染呢?

  没人能够给一个明确的答案,至今业内很多人觉得React的“同构”没有多大意义,但也有很多有志之士开发了很多服务器端渲染的实例。所以,在这里只是介绍“同构”的方法,每个应用都有每个应用的特点,开发者需要根据应用特点作出判断。

  如果应用对TTFP没有那么高的要求,也并不希望对React页面进行搜索引擎优化,那就真没有必要使用“同构”来增加应用复杂度。

  如果希望应用的性能百尺竿头更进一步,而且服务器端运算资源充足,那么可以试一试服务器端渲染。

  React被发明出来就是为了满足浏览器端渲染的需要,我们前面章节的例子也只考虑了React在浏览器端运行的情况,现在我们考虑如何在服务器端使用React。 深入浅出React和Redux

目录
设置
手机
书架
书页
评论