Java那点事儿让前端飞架构算法设计模式和编程理论

浏览器渲染过程与性能优化

2017-10-16  本文已影响154人  SylvanasSun

大家都知道万维网的应用层使用了HTTP协议,并且用浏览器作为入口访问网络上的资源。用户在使用浏览器访问一个网站时需要先通过HTTP协议向服务器发送请求,之后服务器返回HTML文件与响应信息。这时,浏览器会根据HTML文件来进行解析与渲染(该阶段还包括向服务器请求非内联的CSS文件与JavaScript文件或者其他资源),最终再将页面呈现在用户面前。

现在知道了网页的渲染都是由浏览器完成的,那么如果一个网站的页面加载速度太慢会导致用户体验不够友好,本文通过详解浏览器渲染页面的过程来引入一些基本的浏览器性能优化方案。让浏览器更快地渲染你的网页并快速响应从而提高用户体验。

本文作者为: SylvanasSun(sylvanas.sun@gmail.com).转载请务必将下面这段话置于文章开头处(保留超链接).
本文首发自SylvanasSun Blog,原文链接: https://sylvanassun.github.io/2017/10/03/2017-10-03-BrowserCriticalRenderingPath

关键渲染路径


浏览器接收到服务器返回的HTMLCSSJavaScript字节数据并对其进行解析和转变成像素的渲染过程被称为关键渲染路径。通过优化关键渲染路径即可以缩短浏览器渲染页面的时间。

浏览器在渲染页面前需要先构建出DOM树与CSSOM(如果没有DOM树和CSSOM树就无法确定页面的结构与样式,所以这两项是必须先构建出来的)。

DOM树全称为Document Object Model文档对象模型,它是HTMLXML文档的编程接口,提供了对文档的结构化表示,并定义了一种可以使程序对该结构进行访问的方式(比如JavaScript就是通过DOM来操作结构、样式和内容)。DOM将文档解析为一个由节点和对象组成的集合,可以说一个WEB页面其实就是一个DOM

CSSOM树全称为Cascading Style Sheets Object Model层叠样式表对象模型,它与DOM树的含义相差不大,只不过它是CSS的对象集合。

构建DOM树与CSSOM树


浏览器从网络或硬盘中获得HTML字节数据后会经过一个流程将字节解析为DOM树:

整个DOM树的构建过程其实就是: 字节 -> 字符 -> 令牌 -> 节点对象 -> 对象模型,下面将通过一个示例HTML代码与配图更形象地解释这个过程。

<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link href="style.css" rel="stylesheet">
    <title>Critical Path</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div>![](awesome-photo.jpg)</div>
  </body>
</html>
DOM树构建过程

当上述HTML代码遇见<link>标签时,浏览器会发送请求获得该标签中标记的CSS文件(使用内联CSS可以省略请求的步骤提高速度,但没有必要为了这点速度而丢失了模块化与可维护性),style.css中的内容如下:

body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }

浏览器获得外部CSS文件的数据后,就会像构建DOM树一样开始构建CSSOM树,这个过程没有什么特别的差别。

CSSOM树

如果想要更详细地去体验一下关键渲染路径的构建,可以使用Chrome开发者工具中的Timeline功能,它记录了浏览器从请求页面资源一直到渲染的各种操作过程,甚至还可以录制某一时间段的过程(建议不要去看太大的网站,信息会比较杂乱)。

优化关键渲染路径就是在对关键资源、关键路径长度和关键字节进行优化。关键资源越少,浏览器在渲染前的准备工作就越少;同样,关键路径长度和关键字节关系到浏览器下载资源的效率,它们越少,浏览器下载资源的速度就越快。

其他优化方案


除了异步加载JavaScript和使用媒体查询外还有很多其他的优化方案可以使页面的首次加载变得更快,这些方案可以综合起来使用,但核心的思想还是针对关键渲染路径进行了优化。

加载部分HTML


服务端在接收到请求时先只响应回HTML的初始部分,后续的HTML内容在需要时再通过AJAX获得。由于服务端只发送了部分HTML文件,这让构建DOM树的工作量减少很多,从而让用户感觉页面的加载速度很快。

注意,这个方法不能用在CSS上,浏览器不允许CSSOM只构建初始部分,否则会无法确定具体的样式。

压缩


通过对外部资源进行压缩可以大幅度地减少浏览器需要下载的资源量,它会减少关键路径长度与关键字节,使页面的加载速度变得更快。

对数据进行压缩其实就是使用更少的位数来对数据进行重编码。如今有非常多的压缩算法,且每一个的作用领域也各不相同,它们的复杂度也不相同,不过在这里我不会讲压缩算法的细节,感兴趣的朋友可以自己Google。

在对HTMLCSSJavaScript这些文件进行压缩之前,还需要先进行一次冗余压缩。所谓冗余压缩,就是去除多余的字符,例如注释、空格符和换行符。这些字符对于程序员是有用的,毕竟没有格式化的代码可读性是非常恐怖的,但它们对于浏览器是没有任何意义的,去除这些冗余可以减少文件的数据量。在进行完冗余压缩之后,再使用压缩算法进一步对数据本身进行压缩,例如GZIPGZIP是一个可以作用于任何字节流的通用压缩算法,它会记忆之前已经看到的内容,然后再尝试查找并替换重复的内容。)。

HTTP缓存


通过网络来获取资源通常是缓慢的,如果资源文件过于膨大,浏览器还需要与服务器之间进行多次往返通信才能获得完整的资源文件。缓存可以复用之前获取的资源,既然后端可以使用缓存来减少访问数据库的开销,那前端自然也可以使用缓存来复用资源文件。

浏览器自带了HTTP缓存的功能,只需要确保每个服务器响应的头部都包含了以下的属性:

资源预加载


Pre-fetching是一种提示浏览器预先加载用户之后可能会使用到的资源的方法。

使用dns-prefetch来提前进行DNS解析,以便之后可以快速地访问另一个主机名(浏览器会在加载网页时对网页中的域名进行解析缓存,这样你在之后的访问时无需进行额外的DNS解析,减少了用户等待时间,提高了页面加载速度)。

<link rel="dns-prefetch" href="other.hostname.com">

使用prefetch属性可以预先下载资源,不过它的优先级是最低的。

<link rel="prefetch"  href="/some_other_resource.jpeg">

Chrome允许使用subresource属性指定优先级最高的下载资源(当所有属性为subresource的资源下载完完毕后,才会开始下载属性为prefetch的资源)。

<link rel="subresource"  href="/some_other_resource.js">

prerender可以预先渲染好页面并隐藏起来,之后打开这个页面会跳过渲染阶段直接呈现在用户面前(推荐对用户接下来必须访问的页面进行预渲染,否则得不偿失)。

<link rel="prerender"  href="//domain.com/next_page.html">

参考文献


上一篇 下一篇

猜你喜欢

热点阅读