前端性能优化(二)

前端性能优化(二)

前端优化之渲染网页

原文:Optimising the front end for the browser

优化关乎速度与满意度。

  • 从用户体验(UX)角度,我们希望前端页面可以快速加载。
  • 从开发体验(DX)角度,我们希望前端是快速、简洁、规范的。

浏览器如何渲染网页

  • 使用HTML创建文档对象模型(DOM)。
  • 使用CSS创建CSS对象模型(CSSOM)。
  • 基于DOM和CSSOM执行脚本(Script)。
  • 合并DOM和CSSOM形成渲染树(Render Tree)。
  • 使用渲染树布局(Layout)所有元素。
  • 渲染(Paint)所有元素。

fe

步骤一 HTML

浏览器从上到下读取标签,把他们分解成节点,从而创建DOM。

fe

HTML加载优化策略
  • 样式在顶部,脚本在底部。 总体思路是尽可能早的加载样式,尽可能晚的加载脚本。原因是脚本执行之前,需要HTML和CSS解析完成,因此,样式尽可能的往顶部放,当底部脚本开始执行之前,样式有足够的时间完成计算。

  • 最小化和压缩 方法可用于所有内容,包括HTML,CSS,Javascript,图片和其他资源。 最小化是移除所有多余的字符,包括空格,注释,多余的分号,等等。 压缩比如GZip,大大的压缩下载文件的大小。 两种方法都用的情况下,资源加载量大大的减少80%-90%。

  • 无障碍 不会提升页面的下载速度,但会大大提升满意度,给元素加上aria属性,图片加上alt属性。

步骤二 CSS

当浏览器发现任何与节点相关的样式时,比如外部,内部,行内样式,立即停止渲染DOM,并利用这些节点创建CSSOM,这就是CSS“渲染阻塞”的由来。


// 外部样式
<link rel="stylesheet" href="style.css" />
// 内部样式
<style>
h1 {
    font-size: 18px;
}
</style>
// 行内样式
<button style="background-color: blue">按钮</button>

CSSOM节点创建与DOM节点创建类似,随后,两者合并如下:

fe

CSSOM的构建会阻塞页面的渲染,因此我们要尽早的加载样式。

步骤三 Javascript

浏览器不断构建DOM/CSSOM节点,直到发现外部或行内的脚本。由于脚本可能需要访问或操作之前的HTML或样式,我们必须要等他们构建完成。因此浏览器必须停止解析节点,完成构建CSSOM,执行脚本,然后再继续。这就是Javascript被称作为“解析器阻塞”的原因。

脚本只能等到先前的CSS节点构建完成。

fe

Javascript加载优化策略
  • 异步加载脚本 脚本添加async属性,可以通知浏览器不要阻塞其余页面的加载,下载脚本处于较低的优先级。一旦下载完成,就可以执行。

fe

async适用于不影响DOM或CSSOM的脚本,对一些跟我们的代码无关的,不影响用户体验的外部脚本尤其适用,比如分析统计脚本。

  • 延迟加载脚本 deferasync非常类似,不会阻塞页面的加载,但会等到HTML完成解析后再执行。

fe

使用defer策略的另一个好的选择是addEventListener。注意,asyncdefer对于行内的脚本不起作用,浏览器默认会编译执行他们。

  • 操作之前克隆节点 多次操作DOM时可以尝试,首先克隆整个DOM节点更加高效,操作克隆后的节点,然后替换先前的节点,避免了多次重绘,降低CPU和内存消耗,同时也避免了不必要的页面闪烁。注意,克隆的时候并没有克隆事件监听。

步骤四 渲染树

一旦所有的节点已被解析,DOM和CSSOM准备合并,浏览器便会构建渲染树,如果我们把节点想象成单词,那么对象模型就是句子,渲染树就是整个页面。

fe

步骤五 布局

布局阶段需要确定页面上所有元素的大小和位置。

fe

步骤六 渲染

最终的渲染阶段,会真正的光栅化屏幕上的像素,把页面呈现给用户。

fe

整个过程耗时1秒或十分之一秒,我们的任务是让他更快。

如果Javascript事件改变了页面的部分,便会引起渲染树的重绘,并且迫使布局和渲染过程再次进行。

前端优化之网络请求

浏览器如何发起请求

当浏览器请求一个URL,服务端会响应一些HTML。

我们需要认识一个新术语,关键渲染路径(Critical Rendering Path(CRP)),就是浏览器渲染页面的步骤数,如下图。

fe

关键路径长度

关键渲染路径的度量标准是路径长度,最理想的的关键路径长度是1。

如果一个页面包含一些内部样式和Javascript,关键路径会发生以下改变。

fe

新增两步,构建CSSOM和执行脚本,因为我们的HTML有内部样式和脚本需要计算,由于没有外部请求,我们的关键路径长度没变。但是,我们的HTML大小增加到了2kb,某些地方还是有影响的。

关键字节数

三个度量标准之二出现了,关键字节数,他用来衡量渲染页面需要传送多少字节数。

如果你认为不需要外部资源就大错特错了,外部资源可以被缓存。

我们使用一个外部CSS文件,一个外部JavaScript文件,和一个外部带async属性的Javascript文件。关键路径图如下:

fe

浏览器请求页面,构建DOM,发现外部资源后开始下载,CSS和JavaScript有较高的优先级,其他资源次之。

styles.cssapp.js通过另一个关键路径获取。暂时不获取analytics.js,是因为加了async属性,浏览器将用另一个线程下载它,它处于较低优先级,不会阻塞页面渲染,也不影响关键路径。

关键文件

最后一个度量标准就是关键文件,浏览器渲染页面需要下载的文件总量。以上例子,HTML文件,CSS和JavaScript文件算关键文件,async的脚本不算。当然是文件越少越好。

回到关键路径长度

以上例子就是最短的渲染路径么?我认为渲染页面时,我们仅需要下载HTML,CSS和Javascript文件,仅通过两次服务器往返就做到了。

HTTP1 文件限制

我们浏览器的http1协议,在同一个域名,同一次,允许下载的文件数有最大限制,范围从2到6。 通过把一些资源放到影子域名,可以绕过这个限制,以达到最佳优化效果。

注意:不要把关键的CSS放到根域名以外的其它域名,有些场景会对DNS查找和延迟起反作用。

HTTP2

如果网站使用HTTP2,并且用户的浏览器也兼容,则可以完全避免这个下载限制。

TCP往返限制

每一次服务器往返可以传送的最大数据量是14kb,包括所有HTML,CSS和脚本的网络请求。

如果我们HTML,或积累的资源请求超过14kb时,需要多做一次服务器往返。

大魔法师

我们整个HTML页面可以很好的压缩,GZip可以压缩到2kb,远低于14kb的限制,因此,一次服务器往返就可以搞定。

fe

  • 关键路径度量:长度 1,文件数 1,字节数 2kb。

浏览器发现外部资源(CSS和JavaScript)时,发起请求开始下载它们。需要下载的CSS文件是14kb,达到了往返传输的最大限制,因此增加了一条关键路径。

fe

  • 关键路径度量:长度 2,文件数 2,字节数 16kb。

余下的资源低于14kb,但是总共有7个资源,由于网站未启用HTTP2,我们的Chrome,每一次往返仅可以下载6个文件。

fe

  • 关键路径度量:长度 3,文件数 8,字节数 28kb

下载完最终文件,并开始渲染DOM。

fe

  • 关键路径度量:长度 4,文件数 9,字节数 30kb

基于以上的信息和知识,发起每一个链接时,就可以准确地预估页面的性能了。

浏览器网络优化策略

  • Pagespeed Insights 使用Insights鉴别性能问题,Chrome DevTools也有个audit标签。

  • 充分利用Chrome开发者工具 这篇文章值得一读,帮你理解网络资源。

  • 在优质的环境里开发,在艰苦的环境里测试 开发时大可以使用1Tb SSD,32G内存的Macbook Pro,但是性能测试时候还是要到Chrome的network下模拟低带宽的情况,从而获取有价值的信息。

  • 合并资源/文件 基本上,每接受到一个外部CSS和JavaScript文件,浏览器都会构建CSSOM,执行脚本。尽管几个文件可以在一次往返中传送,但也浪费了浏览器的宝贵时间和资源,最好还是合并文件,减少不必要的加载。

  • 首屏内容使用内部样式 内部CSS和Javascript不需要请求外部资源,相反,外部资源可以被缓存,并保持DOM轻量,两者没有非黑即白。

但是一个非常好的论点就是首屏关键内容使用内部样式,可以避免请求额外的资源,节省时间做最有意义的渲染。

  • 最小化/压缩图片
  • 延迟加载图片
  • 异步记载字体
  • 是否真的需要Javascript/CSS?

原生HTML元素可以实现的行为是否用了脚本,是否有样式或图标可以行内创建的,不需要内部/外部资源,比如行内SVG

  • CDN

可以利用CDN(内容分发网络)存储资源,它会从离用户最近,延迟最低的位置分发到用户设备,加载时间更快。

延伸阅读

综述

关键渲染路径是最重要的,它使得网站优化有规律可循。

需要关注的3个指标: 1.关键字节数 2.关键文件数 3.关键路径长度

Done! By suki,引用请注明出处作者。
License CC BY-NC-SA 3.0.

0%