前言
在上篇文章中,我们介绍了一下前端性能指标的类型、含义以及获取方式等等。以此为基准,我们通过不断地实践和优化,逐步建设了一套前端性能监控系统,核心是以「响应速度、页面稳定性、操作延迟」三大方面作为衡量标准,以「FP、FCP、LCP、CLS、FID」五大指标作为分析依据,通过数据聚合和可视化的方式,最终达成监控和分析性能的目的。
性能指标是有了,如果我的web项目性能超出了这些指标标准,该怎么办呢?本篇文章主要聊一下这些数据到底是怎么来的,并且应该怎么优化。所谓“知来处,明去处”,只有这样,才能对前端性能有一个正确和全面的认知。
正文
浏览器工作过程
想要了解各个指标的触发时机,首先需要从浏览器的工作原理开始。从输入网址到展示页面整个过程,看似很简单,其实后面做了很多工作。而浏览器工作主要有两部分构成:浏览器获取过程和浏览器解析过程。
浏览器获取过程
-
输入网址:浏览器根据用户输入的网址或通过链接跳转等方式向服务器发送请求。 在一般情况下,我们访问页面都是输入一个网址,如:www.baidu.com。而不是直接输入IP地址。
-
DNS解析:浏览器通过域名解析得到对应的 IP 地址,向服务器发送请求。 对我们来说,网站是域名,但对计算机来说,它们是 IP 地址,所以必须进行dns查询。最终获得IP地址才能正式发起页面请求。比如我们的直播官网地址:yuerzhibo.com,通过DNS服务器最终会解析成为一个「203.107.43.84」的IP地址。
-
建立TCP连接:当获取到IP地址后,浏览器与服务器进行 TCP 握手,建立连接,开始传输数据。TCP 握手是一种机制,旨在让两个想要相互传递信息的实体(即浏览器和服务器)在传输数据之前协商好连接的参数。对于通过https建立的连接,还需要进行另一次握手,即TLS协商。
-
发送HTTP请求:建立安全连接之后,浏览器会将自身的信息(如浏览器类型、页面语言等)以及请求头发送给服务器,用于请求HTML页面。以我们的官网为例,第一次的页面请求信息如下:
-
服务器响应:服务器接收到请求并返回响应。响应头中包含了内容类型、缓存控制等信息。
-
下载 HTML:浏览器开始下载 HTML 文件,并按顺序读取其中的代码。 服务器响应后,浏览器会逐步下载html文档的内容,如下所示:
-
下载 CSS、js 等文件:浏览器下载页面引用的 CSS 文件、JavaScript 文件等。获取到html文档后,会按顺序读取代码,遇到css,js文件,会依次进行下载。每个文件的下载都会依次执行「浏览器获取过程」。
浏览器解析过程
浏览器的解析过程主要发生在「获取过程-步骤6」html下载完成之后,我们看一下详细情况:
- HTML解析:浏览器读取HTML代码,并将其解析成DOM(文档对象模型)树,该树结构将定义整个文档。
HTML解析主要分为两部分:词法解析和DOM树构建。词法解析就是识别html文档中的字节,转换为字符,然后解析为token,最终识别成为节点,如「div、br、span」等,会依次识别标签上的属性,标识符、文本内容等;DOM树构建就是依据他们的层级嵌套关系组织成为一个树结构,方便后续使用。
- CSS解析:浏览器读取CSS代码,并将其解析成CSSOM(CSS对象模型)树,该树结构将定义CSS样式。
CSS解析和HTML的解析过程类似,同样是逐步将字节逐步转化为节点样式和选择器,最终组织成为一个CSSOM树。
- 执行javascript:在HTML解析的过程中,当浏览器遇到script标签时,会停止解析HTML文档,并进行JavaScript的解析和执行。
遇到JavaScript代码时会暂停解析,去执行脚本,脚本执行完毕后再继续解析下面的HTML文档。这个过程被称为HTML解析和JavaScript解析的交错执行。因此,编写高效的JavaScript代码是保证页面性能的重要因素。
-
渲染树构建:浏览器将DOM树和CSSOM树结合起来构建渲染树。渲染树只包含需要显示的元素和CSS属性,不包含隐藏的元素和属性。
-
布局:浏览器根据渲染树的信息,计算每个元素在页面上的位置和大小。
这个阶段也是我们经常说的回流、重排阶段,元素的增加删除、定位的变化、窗口大小的改变都会重新计算。
- 绘制:根据布局信息,浏览器将页面上需要显示的元素转换为屏幕上的像素,生成位图。
回流完成之后,节点的大小、位置等已经固定,浏览器开始重绘阶段,逐步将元素的每个视觉部分绘制到屏幕上。
- 合成:将不同图层的位图合成成最终的屏幕位图。
正常情况下,我们的页面都是通过CPU来呈现内容,但是一些3D属性、canvas、video等,会在自己的图层进行渲染,会通过GPU来呈现。而浏览器最终会将这些图层进行合成。
整个解析过程如下图所示:
指标触发时机和影响因素
我们已经了解了浏览器的整个工作过程,可以简单总结一下这些指标的触发时机和影响因素。
- FP,浏览器首次将任何像素渲染到屏幕上的时间。在上面的过程中,发生在浏览器「解析过程-步骤6」阶段。主要受到浏览器加载过程、构建dom树、构建cssom树、js代码执行等因素影响。
- FCP,浏览器首次将可见内容绘制到屏幕上的时间,FP在页面开始绘制的时间点上发现问题。而FCP能够更精确地确定用户何时可以看到页面的实际内容。FCP的发生时间会忽略不可见内容的渲染,所以一般会大于等于FP时间。除浏览器加载过程、构建dom树、构建cssom树、js代码执行等因素外,还会受到首次可见内容大小的影响。
- LCP,是指视口内可见的最大内容元素的渲染时间。计算过程如下:
- 找到可见区域内面积最大的元素,以此为依据判断内容是否“有意义”。
- 加载该元素的所有内容,包括文字、图片和视屏等。
- 记录加载该元素所需的时间,并将其作为LCP的值。
主要受到可见区域内面积最大的元素影响。
- FID,是指用户第一次与页面交互到页面做出响应的延迟时间,计算过程如下:
- 当用户首次与页面交互时,记录交互的时间戳。
- 在此时间戳后,查找在主线程上执行的所有工作。
- 找到距离时间戳最近的长任务,并记录该任务的持续时间。
- 将长任务持续时间作为FID的值。
主要受到js代码质量的影响,需要合理安排异步任务。
-
CLS,是指布局位移在视窗内可见像素的比例。计算过程如下:
- 当页面加载时,记录测量区域中所有元素的初始位置和尺寸。
- 当每个元素的尺寸或位置发生变化时,记录变化的指标,如变化量和元素位置。
- 用户在滚动页面时,跟踪可视区域的位置和大小。
主要受到dom代码质量、css代码质量的影响,需要合理布局,降低重排的次数。
如何优化?
优化这些指标,我们主要从三大维度入手:
- 浏览器获取过程。旨在优化【响应速度】
- 浏览器解析过程。旨在优化【响应速度、页面稳定性】
- 代码质量。旨在优化【响应速度、页面稳定性、操作延迟】
那具体应该怎么操作呢?接下来我们一一说明:
1. 缩短服务器响应时间
从输入网址到服务器响应,浏览器和服务器做了很多工作,缩短这里的响应时间可以提升部分性能。
具体包括:
- DNS预解析
- 预连接
- 减少域名访问数量
- 降低接口请求时间
- 使用cdn加载资源
2. 使用缓存
缓存是指在客户端或服务器上存储数据的机制,以便以后访问相同的请求时,可以直接使用缓存的数据,而不用再次请求网站的服务器。使用缓存是一种提高网站性能和用户体验的有效方式。
具体包括:
- HTTP缓存
- 离线包缓存
- CDN缓存
3. 减少页面请求
减少页面请求是提高网站性能和用户体验的重要方式,可以降低网站的加载时间,减少带宽使用和服务器负载,提高用户体验。在保持现有功能的前提下,最有效的减少请求的方法就是合并。
具体包括:
- 合并css、js文件
- 合并图片资源
4. 压缩文件
压缩文件可以有效减小文件的大小,从而减少存储和传输的成本,同时可以提高文件传输的速度和效率。这也是我们最有效的优化方法之一。
具体包括:
- js、css文件压缩
- 图片压缩
- 字体文件压缩
5. 优化加载策略
当代码、图片已经做过合并,并且压缩到极限,我们还可以优化加载策略达到提升性能的目的。在前面我们知道js执行会阻塞页面的渲染,我们可以通过异步加载、异步执行的方式,降低阻塞页面js的大小。
具体包括:
- 使用异步脚本
- 代码分离,按需加载
- 路由懒加载
- 非首屏组件懒加载
- 图片懒加载
- 图片预加载
- 图片分割
- 延迟加载大型内容
6. 优化渲染时间
除了浏览器获取过程外,浏览器解析过程也是很耗时的阶段,我们可以通过提升DOM构建、CSSOM构建、重排、重绘等过程,来实现性能的提升。
具体包括:
- 仅展示可视区域内容
- 使用骨架屏
- 优化html结构
- 降低DOM层级
- 降低CSS层级
7. 降低js执行压力
js的执行会阻塞页面的渲染,同时也会占用客户端的CPU,过高的占用率会导致客户端性能降低,如果在用户操作时,有大量的js代码执行,页面响应就会不及时,用户体验也会很差。所以降低js执行压力可以有效提升性能。
具体包括:
- 路由分包
- 非首屏组件分包
- 耗时任务异步执行
8. 提高代码质量
除了以上的优化手段外,我们还应该逐渐养成优良的代码习惯,保证代码的可维护性,易读性,易用性的同时,还能保证当前代码的性能质量。
具体包括:
- 避免重复代码
- 耗时任务异步执行
- 字体预处理
- 更好的dom编码习惯
- 更好的css编码习惯
为了便于实际开发和优化,我将这些内容做了详细说明和整合。优化效果明显的方法做了重点标注,同时也标注了会受到影响的性能指标。如下图所示,详细操作由于篇幅有限,就不一一赘述了。
尾声
“代码不息,优化不止。”,用户体验越好,成就感就越高,咱们的水平也越高。希望和大家一起重视并学习前端性能的优化和治理。