web性能说白了就是网站打开速度快不快,页面中的动画够不够流畅,表单提交的速度是否快,列表滚动页面切换是否卡顿。性能优化就是让网站变得快。

在MDN上对web性能的定义是网站或应用程序的客观度量和可感知的用户体验。比如减少页面加载事件(减少文件体积,减少HTTP请求,使用预加载),让网站尽快可用(懒加载或者分片加载),平滑的交互性(使用CSS替代JS动画,减少UI重绘),感知表现(加载动画,loading等给用户感觉快),性能测定(性能指标,性能测试,性能监控以便持续优化,毕竟性能优化是个持续的过程)。

页面性能关乎到用户的留存,网站的转换率,用户体验和网站的传播,甚至影响搜索排名遭到用户投诉,当然也会影响开发的效率。

性能指标

进行性能优化之前我们首先要知道要在哪些方面做性能优化。

首先需要了解性能指标,多快的速度才算快呢?可以使用专业的工具可量化的评估出网站或应用的性能表现。

立足于网站页面响应的生命周期,分析出造成较差性能表现的原因,最后进行技术改造,可行性分析等具体的优化措施,持续迭代优化就可以了。

事实上性能是相对的,他并不是绝对的概念。对于一个用户而言在不同的网络环境下访问页面的速度可能是不同的。即使相同的网站在懒加载的情况下也会显得快。

在讨论性能的时候精确地,可量化的指标是很重要的。但是仅仅因为一个度量标准是基于客观准备并且可以定量的d度量的,并不一定意味这些度量是有用的。对于Web开发人员来说,如何恒量一个Web页面的性能一直都是一个难题。

最初,开发人员使用Time to To Byte。DomContentLoaded和Load这些恒量文档加载进度的指标,但他们不能直接反应用户视觉体验。

为了恒量用户视觉体验,Web标准中定义了一些性能指标。这些性能指标被各大浏览器标准化实现,例如First Paint和First Contentful Paint。

还有一些由Web孵化器社区组提出的性能指标,如Largest COntentful Paint, Time to Interactive, First Input Delay, First CPU Idle。

另外还有Google提出的First Meaningful Paint, Speed Index。

百度提出的First Screen Paint。

这些指标之间并不是毫无关联,而是在以用户为中心的目标中不断演进出来的,有的已经不再建议使用,有的被各种测试工具实现,有的则可以作为通用标准可用于生产环境测量的API。

RAIL性能模型

RAIL是Response,Animation,Idle和Load的首字母缩写,是一种由Google Chrome团队于2015年提出的性能模型,用于提升浏览器的用户体验和性能。

RAIL模型的理念是以用户为中心,最终目标并不是让你的网站在任何特定设备上都能运行很快,而是使用户满意。

Response: 应该尽可能快速的响应用户的操作,应在在100ms以内响应用户输入。

Animation: 在展示动画的时候,每一帧应该以16ms进行渲染,这样可以保持动画效果的一致性,并且避免卡顿。

Idle: 当使用js主线程的时候,应该把任务划分到执行时间小于50ms的片段中去,这样可以释放线程以进行用户交互。50ms为单位是为了保证用户在发生操作的100ms内做出响应。

要使网站响应迅速,动画流畅,通常都需要较长的处理时间,但以用户为中心来看待性能问题,就会发现并非所有工作都需要在响应和加载阶段完成,我们完全可以利用浏览器的空闲时间处理可延迟的任务,只要让用户感受不到延迟即可。利用空闲时间处理延迟可减少预加载的数据大小,以保证网站或应用快速完成加载。

Load: 应该在小于1s的时间内加载完成你的网站,并可以进行用户交互。根据网络条件和硬件的不同,用户对性能延迟的理解也有所不同,在3G网络需要花费更多的时间,5s是一个更现实的目标。

基于用户体验的性能指标其中包括一下几个比较重要的性能指标。

  1. FCP (First Contentful Paint)

首次内容绘制,浏览器首次绘制来自DOM的内容的时间,内容必须包括文本,图片,非白色的canvas或svg,也包括带有正在加载中的web字体文本。这是用户第一次看到的内容。

FCP时间(秒) 颜色编码 FPC分数
0 - 2 绿色(快) 75 - 100
2 - 4 橙色(中等) 50 - 74
超过4 红色(慢) 0 - 49
  1. LCP (Largest Contentful Paint)

最大内容绘制,可视区域中最大的内容元素呈现到屏幕上的时间,用以估算页面的主要内容对用户的可见时间。img图片,video元素的封面,通过url加载到的北京,文本节点等,为了提供更好的用户体验,网站应该在2.5s以内或者更短的时间最大内容绘制。

LCP时间(秒) 颜色编码
0 - 2.5 绿色(快)
2.5 - 4 橙色(中等)
超过4 红色(慢)
  1. FID (First Input Delay)

首次输入延迟,从用户第一次与页面进行交互到浏览器实际能够响应该交互的时间,输入延迟是因为浏览器的主线程正忙于做其他事情,所以不能响应用户,发生这种情况的一个常见原因是浏览器正忙于解析和执行应用程序加载的大量计算的JavaScript。

FID时间(毫秒) 颜色编码
0 - 100 绿色(快)
100 - 300 橙色(中等)
超过300 红色(慢)
  1. TTI (Time to Interactive)

网页第一次完全达到可交互状态的时间点,浏览器已经可以持续的响应用户的输入,完全达到可交互的状态的时间是在最后一个长任务完成的时间,并且在随后的5秒内网络和主线程是空闲的。从定义上来看,中文名称叫持续可交互时间或可流畅交互时间更合适。

TTI时间(秒) 颜色编码
0 - 3.8 绿色(快)
3.9 - 7.3 橙色(中等)
超过7.3 红色(慢)
  1. TBT (Total Block Time)

总阻塞时间,度量了FCP和TTI之间的总时间,在该时间范围内,主线程被阻塞足够长的时间以防止输入响应。只要存在长任务,该主线程就会被视为阻塞,该任务在主线程上运行超过50
毫秒。

线程阻塞是因为浏览器无法中断正在进行的任务,因此如果用户确实在较长的任务中间与页面进行交互,则浏览器必须等待任务完成才能响应。

TBT时间(毫秒) 颜色编码
0 - 300 绿色(快)
300 - 600 橙色(中等)
超过600 红色(慢)
  1. CLS (Cumulative Layout Shift)

累计布局便宜,CLS会测量在页面整个生命周期中发生的每个意外的布局移位的所有单独布局移位分数的总和,他是一种保证页面的视觉稳定性从而提升用户体验的指标方案。

用人话来说就是当我们想点击页面中的某个元素的时候,突然布局变了,手指点到了其它位置。比如想点击页面的链接,突然出现了一个banner。这种情况可能是因为尺寸未知的图像或者视频。

CLS时间(毫秒) 颜色编码
0 - 0.1 绿色(快)
0.1 - 0.25 橙色(中等)
超过0.25 红色(慢)

Web Vitals

这也是谷歌指定的web性能指标标准, 谷歌认为之前的标准太复杂,指标太多了,在2020年重新进行了梳理,简化到了三个。加载性能LCP,交互性FID,视觉稳定性CLS。只需要做好这三个,网站的性能基本上就可以了。

测量Web Vitals的工具有很多,比如Lighthouse, web-vitals, 浏览器插件web vitals。

// npm install web-vitals -g

import { getLCP, getFID, getCLS } from 'web-vitals';

getCLS(conole.log)
getFID(conole.log)
getCLS(conole.log)

谷歌浏览器可以直接在插件市场中查找并且安装web vitals。安装完成之后浏览器的右上角会多出插件标志,点击就会显示页面的性能指标。

性能测试

性能检测是作为性能优化过程中的一环,他的目的通常是给后续优化工作提供指导方向,参考基线以及千户对比的依据。性能检测并不是一次性执行结束后就完成的工作,他会在检测,记录和改进的迭代过程中不断重复。来协助网站的性能优化不断接近期望的效果。

Lighthouse是谷歌开发并开源的web性能测试工具,用于改进网络应用的质量,可以将其作为一个Chrome扩展程序运行,或从命令行运行。只需要为其提供一个需要审查的地址,Lighthouse就会对页面进行一连串的测试,生成一个有关页面性能的报告。

在浏览器的调试工具中默认就存在lighthouse选项,只需要切换至lighthouse, 在右侧的选项区选中我们需要的选项。点击生成报告。

屏幕快照 2021-06-16 14.22.33.png

可以看到淘宝的首屏时间是0.6s,可交互时间是1.5s,总阻塞时间是10ms。最大绘制时间是1s。通过这些指标就可以看到在哪方面存在性能瓶颈。

屏幕快照 2021-06-16 14.26.33.png

在下方会对渲染进行拍照截图,如果空白页面较多也能体现网站白屏时间过长。下面还会给一些优化建议。比如某些资源过大,加载时间过长等,当然这些建议不并一定都是对的,只是一些建议。

屏幕快照 2021-06-16 14.29.16.png

最后是测试环境信息,不能制作一种环境的测试,要多环境测试。

屏幕快照 2021-06-16 14.32.06.png

在线web性能测试工具(https://www.webpagetest.org), 提供多地点测试。他只能测试已经发布了的网站。输入需要测试的网页地址,点击start test按钮就开始测试了,可以选择测试地理位置,测试的浏览器等。

屏幕快照 2021-06-16 14.42.45.png

屏幕快照 2021-06-16 14.45.05.png

这里会生成一份详细的测试数据,我这里没打开,打开再补图吧,尴尬…

Chrome DevTools

可以查看当前Chrome浏览器中,所有进程关于GPU,网络和内存空间的使用情况,这些进程包括当前打开的各个标签页,安装的各种扩展插件,以及GPU,网络,渲染等浏览器的默认进程,通过监控这些数据,可以定位可能存在内存泄露或网络资源加载异常的问题进程。

更多工具 -> 任务管理器

屏幕快照 2021-06-16 15.02.04.png

可以看到所有进行的进程,可以看到内存占用网络消耗。

Network面板是一个常被用到的工具,通过它可以获取到网站所有资源的请求情况,包括加载时间,尺寸大小,优先级设置以及HTTP缓存等信息。可以帮助开发者发现可能由于未进行有效压缩而导致资源尺寸过大的问题,未配置缓存策略导致二次请求加载时间过长的问题。

屏幕快照 2021-06-16 15.04.35.png

1.缓存测试

Disable cache

屏幕快照 2021-06-16 15.08.47.png

2.吞吐测试,模拟网速

屏幕快照 2021-06-16 15.10.08.png

监控并统计出网站应用运行过程中代码执行的覆盖率情况。

统计的对象是JavaScript脚本文件与css样式文件,统计结果主要包括文件的字节大小,执行过程中已覆盖的代码字节数,可视化的覆盖率条形图。

根据执行结果可以发现到底哪些尺寸较大的代码文件覆盖率较低,这就意味着这些代码文件中可能存在较多的无用代码。

Ctrl + shift + p 搜索 coverage 就会显示出来。

屏幕快照 2021-06-16 15.18.59.png

可以看到第一个文件有58%没有被使用到,第二个有95.2%没有使用到。

屏幕快照 2021-06-16 15.21.02.png

主要用于分析内存占用情况,如果出现内存泄露,那么就可能带来网站崩溃的后果。

为了更细致和准确的监控应用网站当前的内存使用情况,Chrome浏览器提供Memory面板,可以快速生成当前的堆内存快照。

屏幕快照 2021-06-16 16.25.26.png

结束后可以查看到内存占用大小,就可以对对应的模块进行优化。

屏幕快照 2021-06-16 16.26.46.png

使用Performance面板主要对网站应用的运行时性能表现进行检测和分析,包括页面的每秒帧数,CUP的消耗和各种请求花费的时间。

2021616-163344.png

点击开始后等待两三秒就可以停止了。

屏幕快照 2021-06-16 16.35.58.png

这里面就可以统计出网站的信息。

屏幕快照 2021-06-16 16.37.43.png

另一个非常方便的工具是FPS计数,可以在页面运行时提供对FPS的实时估计。

Ctrl + Shift + P 输入 fps 选择显示渲染。就会在浏览器中出现监控面板。

屏幕快照 2021-06-16 16.43.01.png

还可以使用性能监视器,这是一个事实的监视器。

Ctrl + Shift + P 输入 monitor

屏幕快照 2021-06-16 16.46.24.png

性能优化路径

说前端优化之前先从这样一个问题开始说起。当浏览器地址栏输入url按下回车,整个过程都发生了什么。性能优化基本也是围绕这个过程展开的。

首先浏览器接收到URL,到网络请求线程的开启,一个完整的HTTP请求发出,服务器接收到请求并转到具体的处理服务,前后台之间的HTTP交互和涉及的缓存机制,浏览器接收到数据包的关键渲染路径,js引擎的解析过程。大致就是这样一个过程。

下面我们来详细说说。

浏览器接收到输入的URL到开启网络请求线程,这个阶段是在浏览器内部完成的。那么什么是线程什么是进程呢?

简单来说,进程就是一个程序运行的实例,操作系统会为进程创建独立的内存,用来存放运行所需的代码和数据,而线程是进程的组成部分,每个进程至少有一个主线程及可能的若干子线程,这些线程由所需的进程进行启动和管理。

由于多个线程可以共享操作系统为其所属的同一个进程所分配的资源,所以多线程的并行处理能有效提高程序的运行效率。

只要某个线程执行出错,将会导致整个程序崩溃。进程与进程之间相互隔离,这保证了当一个进程挂起或崩溃的情况发生时并不会影响其他进程的正常运行,虽然每个进程只能访问系统分配给自己的资源,但可以通弄过IPC机制进行进程间通信。

进程所占用的资源会在其关闭后由操作系统回收,即使进程中存在某个线程产生的内存泄露,当进程退出时相关的内存资源也会被回收。线程之间可以共享所属进程的数据。

早期浏览器都是单进程的,其中的页面渲染,呈现,网络请求都通过线程来实现。前面说了只要一个线程崩溃就会导致整个进程崩溃。如果你上网较早应该有过这样的体会,一个网站卡死了整个浏览器都卡死了。单进程的浏览器存在很多的隐患,比如页面流畅度,安全性,稳定性都比较低。

后来Chrome推出了多进程浏览器,一个浏览器只有一个主进程,负责菜单栏,标题栏等页面显示,文件访问,前进后退以及子进程管理。除主进程外还有GPU进程,插件进程,网络进程,渲染进程。

渲染进程也称为浏览器内核,默认会为每个标签页开辟一个独立的渲染进程,负责将HTML,CSS,JavaScript等资源转为可交互的页面,其中包含多个子线程,js引擎线程,GUI渲染线程,事件触发线程,定时触发器线程,异步http请求线程等。当打开一个标签页输入URL后所发起的网络请求就是从这个进程开始的,处于安全的考虑渲染进程存在于沙箱中。打开Chrome的任务管理器可以从中发现这些进程。

建立HTTP请求这个阶段主要分为两部分,DNS解析和通信链路的建立。简单来说首先发起请求的客户端浏览器要明确知道所要访问的服务器地址,然后建立通往该服务器地址的路径。

DNS解析说白了就是根据host域名找到具体的IP地址,中间会经历很多的环节。

首先会查找浏览器的缓存,如果找不到就去查找系统自身的DNS缓存,在没有就去查找系统的hosts文件,再找不到就去本地域名服务器提供商查询根域名服务器,如果还是找不到就去查找com顶级域名服务器,最后会去权限域名服务器查找,都没有找到就返回报错信息。这就是DNS查找的过程,其中任何一个环节慢了都会影响后续的操作。

在通过DNS解析到目标服务器IP地址后,就可以简历网络连接进行资源的访问。在这个过程中涉及到网络架构模型,国际标准化组织提出了一些网络架构的模型,OSI、TCP/IP。

OSI是七层架构,包括应用层,表示层,会话层,传输层,网络层,数据链路层,物理层。TCP/IP简化到了四层,应用层,传输层,网络层,数据链路层。同样每一层慢了对性能都有影响。

经过网络模型之后就要建立TCP链接,主要是为了通过http对数据进行请求和发送。

由于TCP是面向有链接的通信协议,所以在传输数据之前需要建立好客户端与服务间的链接,即通常所说的三次握手。

当TCP链接建立好以后,便可通过HTTP等协议进行前后端的通信,但在实际的应用中,并非浏览器与确定IP地址的服务器之间直接通信,往往会在中间加入反向代理服务器。

反向代理服务器根据客户的请求,从后端服务器上获取资源后提供给客户端,反向代理通过会做下面一些事,比如负载均衡,安全防火墙,加密及SSL加速,数据压缩,解决跨域,静态资源缓存。

请求经过反向代理服务器收到请求后,首先会有一层统一的验证环节,如跨域验证,安全拦截等,如果发现是不规则的请求则直接返回相应的拒绝报文。

通过验证后才会进入具体的后天程序代码执行阶段,如具体的计算数据库的操作等。

完成计算之后,后台会以一个HTTP响应数据包的形式发送回请求的前端,解说此次请求。

HTTP是建立在传输层TCP协议上的应用层协议,在TCP层面上存在长链接和短连接的区别。

所谓长链接就是在客户端与服务器端简历TCP连接上可以连续发送数据包,但需要双方发送心跳检查包来维持这个链接。

短连接就是当客户端需要向服务器发送请求时,会在网络层IP协议之上建立一次链接,当请求发送并收到响应后,则断开此链接。

HTTP1.0时默认使用短连接。

HTTP1.1时默认使用长链接,但是长链接存在并发数,如果请求过多仍旧需要等待。常用的做法是将域名进行拆分,对小图标进行合并。

HTTP2.0之后便可以在一个TCP链接上请求多个资源,分割成更小的帧请求的性能再次提成。

基于HTTP的缓存分为强缓存和协商缓存。

强缓存就是当浏览器判断出本地缓存未过期时,直接取本地缓存,无需发起请求,此时的状态为200 from cache,在HTTP1.1版本后通过头部的cache-control max-age属性值规定的过期时长来判断缓存是否失效,这比之前使用expires过期时间更准确并且安全。

协商缓存则需要浏览器发起HTTP请求,来判断浏览器本地缓存的文件是否改变。

当经历了网络请求过程,从服务器获取到了所访问的页面文件之后,浏览器便要开始渲染服务器响应回来的内容。

首先浏览器会通过解析HTML和CSS文件来构建DOM和CSSOM。

浏览器接收读取到HTML文件,其实是根绝文件指定编码的原始字节,首先需要将字节转换为字符串,再将字符串转换为W3C标准规定的令牌结构,令牌就是HTML中不同标签代表不同含义的一组规则结构。然后经过词法分析将令牌转化为定义了属性和规则值的对象,最后将这些标签根据HTML表示的父子关系,连接成树形结构。

DOM树表示文档标记的属性和关系,但未包含其中各元素经过渲染后的外观呈现,这边是接下来CSSOM的职责了,与将HTML文件解析为文档对象模型的过程类似,CSS文件也会首先经历从字节到字符串,然后令牌化及词法分析后构建为层叠样式表对象模型。

这两个对象模型的构建过程是会花费时间的,可以通过浏览器的开发者工具性能选项卡查看到对应过程的耗时情况。

得到文档对象模型和层叠样式表对象之后就要进行绘制,呈现之前浏览器需要将文档对象模型和样式模型合并到一起最终形成一颗渲染树。这棵树中只包含可见的节点,比如display为node的节点就是不包含的。

从所生成的DOM树的根节点开始向下遍历每个子节点,忽略所有不可见的节点,因为不可见的节点不会出现在渲染树中。

在CSSOM中为每个可见的子节点找到对应的规则并应用。

布局节点根据所得到的渲染树,计算他们在试图设备中的具体位置和大小,这一步输出的是一个盒模型。绘制节点将每个节点的具体绘制方案转化为屏幕上的实际像素。

构建渲染树,布局,及绘制过程所需要的时间取决于实际文档的大小。文档过大,浏览器需要处理的任务就越多样式也复杂,绘制需要的时间就越长。所以关键渲染路径执行快慢,将直接影响首屏加载时间的性能指标。

当首屏渲染完成胡,用户在和网站的交互过程中,有可能通过JavaScript代码提供的用户操作接口更改渲染树的结构。一旦DOM结构发生改变,这个渲染过程就会重新执行一遍。

关键渲染路径的优化不仅是首屏性能,还有交互性能。

转载须知

如转载必须标明文章出处文章名称文章作者,格式如下:

转自:【致前端 - https://madaozhijian.com】 前端性能测试工具  "隐冬"