React 官网为什么那么快?

语言: CN / TW / HK
ead>

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

当我们打开 React 官网时,会发现从浏览器上输入url 到页面首屏完全展示这一过程所花的时间极其短暂,而且在点击页面中的链接切换路由时非常顺滑,几乎页面可以做到“秒切”的效果,根本不会出现卡顿等待的情况,于是带着敬畏之心对“react到底是怎么做到的”的问题开始了本次探索,发现其主要有以下的优化手段

服务端 SSR 渲染

下面是react官方中文文档首页的截图,大家注意下方的红色区域,后面会作为推断的一个理由

当我们打开控制台之后,点击network并选择 DOC文档请求,就会发现有一个请求路径为https://react.docschina.org/GET请求,响应结果为一个 html文档,里面刚好能找到对应上图中红色区域文字的文本,这也就佐证了这个html文档所对应的页面就是react官网首页,而这种渲染页面的方式就称之为服务端 SSR渲染

很多人会将客户端渲染 CSR与 服务端渲染 SSR弄混,下面我们简单介绍一下它们各自的特点,看完之后相信你就能够了解他们的区别了

页面的渲染流程

在开始之前,我们先来回顾一下页面最基本的渲染流程是怎么样的?

  • 浏览器通过请求得到一个 HTML文本
  • 渲染进程解析 HTML 文本,构建 DOM
  • 浏览器解析 HTML 的同时,如果遇到内联样式或者样本样式,则下载并构建样式规则(stytle rules)。若遇到 Javascript 脚本,则会下载并执行脚本
  • DOM 树和样式规则构建完成之后,渲染进程将两者合并成渲染树(render tree
  • 渲染进程开始对渲染树进行布局,生成布局树(layout tree
  • 渲染进程对布局树进行绘制,生成绘制记录
  • 渲染进程对布局树进行分层,分别栅格化每一层并得到合成帧
  • 渲染进程将合成帧发送给 GPU 进程将图像绘制到页面中

可以看到,页面的渲染其实就是浏览器将HTML文本转化为页面帧的过程

客户端渲染 CSR

而如今我们大部分 WEB 应用都是使用 JavaScript 框架(VueReactAngular)进行页面渲染的,也就是说,在执行 JavaScript 脚本之前,HTML 页面已经开始解析并且构建 DOM 树了,JavaScript 脚本只是动态的改变 DOM 树的结构,使得页面成为希望成为的样子,这种渲染方式叫动态渲染,也可以叫客户端渲染 CSRclient side render

下面代码为浏览器请求 react 编写的网页时响应回的代码,返回的 HTML 其实只是一个空壳,里面并没有具体的文本内容,需要执行 JavaScript 脚本之后才会渲染我们真正想要的页面

```html

Jira任务管理系统

```

服务端渲染 SSR

顾名思义,服务端渲染就是在浏览器请求页面 URL 的时候,服务端将我们需要的 HTML 文本组装好,并返回给浏览器,这个 HTML 文本被浏览器解析之后,不需要经过 JavaScript 脚本的执行,即可直接构建出希望的 DOM 树并展示到页面中。这个服务端组装HTML的过程,叫做服务端渲染

下面是服务端渲染时返回的 HTML 文档,由于代码量实在是太多,所以只保留了有象征意义的部分代码,但不难发现,服务端渲染返回的 HTML 文档中是具有页面中的核心文本的

```html


一次学习,跨平台编写

无论你现在使用什么技术栈,在无需重写现有代码的前提下,通过引入 React 来开发新功能。

React 还可以使用 Node 进行服务器渲染,或使用 React Native 开发原生移动应用。

```

现在我们就可以回答为什么react官网要使用服务端渲染了?

因为相对于客户端渲染,服务端渲染在浏览器请求URL之后已经得到了一个带有数据的HTML文本,浏览器只需要解析HTML,直接构建DOM树就可以。而客户端渲染,需要先得到一个空的HTML页面,这个时候页面已经进入白屏,之后还需要经过加载并执行 JavaScript、请求后端服务器获取数据、JavaScript 渲染页面几个过程才可以看到最后的页面。特别是在复杂应用中,由于需要加载 JavaScript脚本,越是复杂的应用,需要加载的 JavaScript脚本就越多、越大,这会导致应用的首屏加载时间非常长,从而降低了体验感

总结

无论是服务端渲染还是客户端渲染,一开始都是要请求一个 HTML 文本,但是区别就在于这个文本是否已经被服务端组装好了

  • 客户端渲染还需要去下载和执行Javascript脚本之后才能得到我们想要的页面效果,所以速度会比服务端渲染慢很多
  • 服务端渲染得到的HTML文档就已经组合好了对应的文本,浏览器请求到之后直接解析渲染出来即可,不需要再去下载和执行额外的Javasript 脚本,所以速度会比客户端渲染快很多

下图是客户端渲染和服务端渲染的流程图:

一些预加载/预处理资源的方式

研究完首屏渲染之后,我们再来研究一下路由跳转后内容的切换。经常看 react 文档的朋友可能早就发现了,其路由跳转无比丝滑,感觉就像是一个静态页面一样,完全没有发送网络请求的痕迹,比如我现在处在hook 简介这一个板块,当我点击 hook 规则 目录之后

发现页面瞬间秒切了过去,内容也瞬间展现在了出来,没有一丝卡顿,用户体验直接爆炸,这到底是怎么做到的呢?

下面我们就来一点一点分析它的每个优化手段

preload

在当前页面中,你可以指定可能或很快就需要的资源在其页面生命周期的早期——浏览器的主渲染机制介入前就进行预加载,这可以让对应的资源更早的得到加载并使用,也更不易阻塞页面的初步渲染,进而提升性能

关键字 preload 作为元素 <link> 的属性 rel的值,表示用户十分有可能需要在当前浏览中加载目标资源,所以浏览器必须预先获取和缓存对应资源 。下面我们来看一个示例:

<link as="script" rel="preload" href="/webpack-runtime-732352b70a6d0733ac95.js">

这样做的好处就是让在当前页面中可能被访问到的资源提前加载但并不阻塞页面的初步渲染,进而提升性能

下面是 react文档中对 preload关键字的使用,告诉浏览器等等可能需要这个资源,希望能够尽早下载下来

可以预加载的资源有很多,现在浏览器支持的主要有: