Web性能指标模型
一、RAIL 模型
RAIL 是 Response、Animation、Idle 和 Load 的首字母缩写,是一种由 Google Chrome 团队于 2015 年提出的性能模型,用于提升浏览器内的用户体验和性能。
-
Response(响应):在 内处理事件
目标:在 100 ms内完成由用户输入发起的转换,让用户感觉交互是即时的。
-
Animatio(动画): 在 内生成一帧,目的为流畅的视觉效果
在 10 毫秒或更短的时间内生成动画的每一帧。从技术上来讲,每帧的最大预算为 16 ms(1000 ms/每秒 60 帧≈16 ms),但是,浏览器需要大约 6 ms速来渲染一帧,因此,准则为每帧 10ms。 -
Idle(空闲):最大限度增加空闲时间
最大限度增加空闲时间以提高页面在 50 ms内响应用户输入的几率 -
Load(加载):在5s内交付并实现可交互
目前,对于,在使用速度较慢 3G 连接的中端移动设备上,理想的目标是在 或更短的事件内实现交互
对于后续加载,理想的目标是在 内加载页面。
二、基于用户体验的性能指标
基于用户体验的核心指标 是 Google 在 web.dev 提出的
1. FCP (First Contentful Paint, 首次内容绘制)
含义
首次内容绘制 (FCP) 指标测量页面从开始加载到页面内容的任何部分在屏幕上完成渲染的时间。对于该指标,"内容"指的是文本、图像(包括背景图像)、<svg>元素或非白色的<canvas>元素。
指标
测量方式
- web-vitals
import {getFCP} from 'web-vitals';
// 当 FCP 可用时立即进行测量和记录。
getFCP(console.log);
- lighthouse
- chrome 开发者工具
优化方案 ☞
- 消除阻塞渲染的资源
- 缩小 CSS
- 移除未使用的 CSS
- 预连接到所需的来源
- 减少服务器响应时间 (TTFB)
- 避免多个页面重定向
- 预加载关键请求
- 避免巨大的网络负载
- 使用高效的缓存策略服务静态资产
- 避免 DOM 过大
- 最小化关键请求深度
- 确保文本在网页字体加载期间保持可见
2. LCP (Largest Contentful Paint, 最大内容绘制)
含义
最大内容绘制 (LCP) 指标会根据页面首次开始加载的时间点来报告可视区域内可见的最大图像或文本块完成渲染的相对时间。
指标
测量方法
import {getLCP} from 'web-vitals';
// 当 LCP 可用时立即进行测量和记录。
getLCP(console.log);
影响因素
- 的服务器响应速度
- JavaScript 和 CSS 渲染阻塞
- 资源加载时间
- 客户端渲染
优化方案☞
- 使用 PRPL 模式做到即时加载
- 优化关键渲染路径
- 优化您的 CSS
- 优化您的图像
- 优化网页字体
- 优化您的 JavaScript(针对客户端渲染的网站)
3. FID (First Input Delay,首次输入延迟)
含义
FID 测量从用户第一次与页面交互(例如当他们单击链接、点按按钮或使用由 JavaScript 驱动的自定义控件)直到浏览器对交互作出响应,并实际能够开始处理事件处理程序所经过的时间。
- 上方的可视化图表中显示的是一个页面,该页面正在发出数个网络请求来获取资源(多为 CSS 和 JS 文件),这些资源下载完毕后,会在主线程上进行处理。这就导致主线程会阶段性地处于忙碌状态(在图中表示为米黄色任务块)
- 较长的首次输入延迟通常发生在首次内容绘制 (FCP)和Time to Interactive 可交互时间 (TTI)之间,因为在此期间,页面已经渲染出部分内容,但交互性还尚不可靠。
- 如果用户在最长的任务刚开始时就尝试与页面进行交互,因为输入发生在浏览器正在运行任务的过程中,所以浏览器必须等到任务完成后才能对输入作出响应。浏览器必须等待的这段时间就是这位用户在该页面上体验到的 FID 值。
指标
测量方法
import {getFID} from 'web-vitals';
// 当 FID 可用时立即进行测量和记录。
getFID(console.log);
优化方案☞
4. TTI (Time to Interactive, 可交互时间)
含义
TTI 指标测量页面从开始加载到主要子资源完成渲染,并能够快速、可靠地响应用户输入所需的时间
- ① 先进行First Contentful Paint 首次内容绘制 (FCP)。
- ② 沿时间轴正向搜索时长至少为 5 秒的安静窗口,其中,安静窗口的定义为:没有长任务且不超过两个正在处理的网络 GET 请求。
- ③ 沿时间轴反向搜索安静窗口之前的最后一个长任务,如果没有找到长任务,则在 FCP 步骤停止执行。
- ④ TTI 是安静窗口之前最后一个长任务的结束时间(如果没有找到长任务,则与 FCP 值相同)。
指标☞
TTI指标(单位:秒) | 颜色编码 |
---|---|
0-3.8 | 绿色(快速) |
3.9-7.3 | 橙色(中等) |
>7.3 | 红色(慢) |
优化方案
5. TBT (Total Blocking Time, 总阻塞时间)
含义
总阻塞时间 (TBT) 指标测量First Contentful Paint 首次内容绘制 (FCP)与Time to Interactive 可交互时间 (TTI)之间的总时间,这期间,主线程被阻塞的时间过长,无法作出输入响应。
长任务:在主线程上运行超过 50 ms的任务。
虽然在主线程上运行任务的总时间为 560(250+90+35+30+155 = 560) 毫秒,但其中只有 345(200+40+105 = 345) 毫秒被视为阻塞时间
指标☞
TBT指标(单位:毫秒) | 颜色编码 |
---|---|
0-200 | 绿色(快速) |
200-600 | 橙色(中等) |
>600 | 红色(慢) |
优化方案
6. CLS (Cumulative layout shift, 累计布局偏移)
含义
测量页面在开始加载和其生命周期状态变为隐藏期间发生的所有意外布局偏移的累积分数。
每当一个可见元素的位置从一个已渲染帧变更到下一个已渲染帧时,就发生了布局偏移。
指标
布局偏移分数 = 影响分数 * 距离分数
- 影响分数是0.75(红色虚线矩形框表示两帧中元素的可见区域集合,在本示例中,该集合占总可视区域的 75%,因此其影响分数为0.75 。)
- 距离分数是0.25 (最大的可视区域尺寸维度是高度,不稳定元素的位移距离为可视区域高度的 25%,因此距离分数为 0.25)
- 所以布局偏移分数是0.75 * 0.25 = 0.1875 。
测量方法
import {getCLS} from 'web-vitals';
// 在所有需要汇报 CLS 的情况下
// 对其进行测量和记录。
getCLS(console.log);
优化方案☞
- 始终在您的图像和视频元素上包含尺寸属性,或者通过使用CSS 长宽比容器之类的方式预留所需的空间。
- 除非是对用户交互做出响应,否则切勿在现有内容的上方插入内容。
- 首选转换动画,而不是触发布局偏移的属性动画
7. SI
含义
指标
测量方法
优化方案
三、Web vitals
Web Vitals,即 Google 给的定义是一个良好网站的基本指标(Essential metrics for a healthy site)
Chorme network下Finish、DOMContentLoaded, Load参数含义
- Finish: 页面上所有 http 请求发送到响应完成的时间。如果页面加载完后,触发了http请求,那么该时间会变更。
-
DOMContentLoaded:DOM 树构建完成。即 HTML 页面由上向下解析 HTML 结构到末尾的封闭标签·
</html>
。但像 <img> 和样式表之类的外部资源
可能尚未加载完成。 - Load:浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式等
Finish 与 DOMContentLoaded 和 Load 并无直接关系
DOMContentLoaded 触发时机
-
无JS和CSS
-
只有CSS
-
有JS和CSS
外部样式表不会影响 DOM,因此 DOMContentLoaded 不会等待它们。
但这里有一个陷阱。如果在样式后面有一个脚本,那么该脚本必须等待样式表加载完成:
<link type="text/css" rel="stylesheet" href="style.css">
<script>
// 在样式表加载完成之前,脚本都不会执行
alert(getComputedStyle(document.body).marginTop);
</script>
首屏时间和白屏时间
白屏时间
白屏时间 = 地址栏输入网址后回车 - 浏览器出现
影响白屏时间的因素:网络,服务端性能,前端页面结构设计。
通常认为浏览器开始渲染 <body> 或者解析完 <head> 的时间是白屏结束的时间点。
首屏时间
首屏时间 = 地址栏输入网址后回车 - 浏览器
影响首屏时间的因素:白屏时间,资源下载执行时间。
关于首屏时间是否包含图片加载网上有不同的说法。
Performance Api
Navigation Timing Level 1
字段 | 含义 |
---|---|
memory | |
jsHeapSizeLimit | 上下文内可用堆的最大体积 |
totalJSHeapSize | 已分配的堆体积 |
usedHeapSize | 当前js堆活跃段的体积 |
navigation | |
redirectCount | 重定向次数 |
type | 如何导航至此页面: 0:点击链接,书签,表单提交,脚本操作,url中直接输入地址 1:点击刷新或者Location.reload() 2:浏览器历史记录,前进后退 255:其他方式 |
timing | |
connectEnd | HTTP(TCP) 完成建立连接的时间(完成握手),如果是持久连接,则与 fetchStart 值相 注意如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接完成的时间 注意这里握手结束,包括安全连接建立完成、SOCKS 授权通过 |
connectStart | HTTP(TCP) 开始建立连接的时间,如果是持久连接,则与 fetchStart 值相等 注意如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接开始的时间 |
domComplete | DOM 树解析完成,且资源也准备就绪的时间,Document.readyState 变为 complete,并将抛出 readystatechange 相关事件 |
domContentLoadedEventEnd | DOM 解析完成后,网页内资源加载完成的时间(如 JS 脚本加载执行完毕),触发DOMContentLoaded事件 |
domContentLoadedEventStart | DOM 解析完成后,网页内资源加载开始的时间 在 DOMContentLoaded 事件抛出前发生 |
domInteractive | 完成解析 DOM 树的时间,Document.readyState 变为 interactive,并将抛出 readystatechange 相关事件 注意只是 DOM 树解析完成,这时候并没有开始加载网页内的资源 |
domLoading | 开始解析渲染 DOM 树的时间,此时 Document.readyState 变为 loading,并将抛出 readystatechange 相关事件 |
domainLookupEnd | DNS 域名查询完成的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等 |
domainLookupStart | DNS 域名查询开始的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等 |
fetchStart | 浏览器准备好使用 HTTP 请求抓取文档的时间,这发生在检查本地缓存之前 |
loadEventEnd | load 事件的回调函数执行完毕的时间 |
loadEventStart | load 事件发送给文档,也即 load 回调函数开始执行的时间 注意如果没有绑定 load 事件,值为 0 |
navigationStart | 在同一个浏览器上下文中,前一个网页(与当前页面不一定同域)unload 的时间戳,如果无前一个网页 unload ,则与 fetchStart 值相等 |
redirectEnd | 最后一个 HTTP 重定向完成时的时间。有跳转且是同域名内部的重定向才算,否则值为 0 |
redirectStart | 第一个 HTTP 重定向发生时的时间。有跳转且是同域名内的重定向才算,否则值为 0 |
requestStart | HTTP 请求读取真实文档开始的时间(完成建立连接),包括从本地读取缓存 连接错误重连时,这里显示的也是新建立连接的时间 |
responseEnd | HTTP 响应全部接收完成的时间(获取到最后一个字节),包括从本地读取缓存 |
responseStart | HTTP 开始接收响应的时间(获取到第一个字节),包括从本地读取缓存 |
secureConnectionStart | HTTPS 连接开始的时间,如果不是安全连接,则值为 0 |
unloadEventEnd | 和 unloadEventStart 相对应,返回前一个网页 unload 事件绑定的回调函数执行完毕的时间戳 |
unloadEventStart | 前一个网页(与当前页面同域)unload 的时间戳,如果无前一个网页 unload 或者前一个网页与当前页面不同域,则值为 0 |
Navigation Timing Level 2
Level 2标准废弃了level 1的timing和navigation这两个接口,取而代之的是定义了 PerformanceNavigationTiming 对象
window.performance.getEntriesByType("navigation")[0]
常用来计算的参数
TTFB 首字节时间
TTFB(Time To First Byte):从发送请求到数据返回第一个字节所消耗时间
const { responseStart, requestStart } = performance.timing
const TTFB = responseStart - requestStart
FP 首次绘制
FP(First Paint) :第一个像素绘制到页面上的时间
const paint = performance.getEntriesByType('paint')
const FP = paint[0].startTime
FCP 首次内容绘制
FCP (First Contentful Paint) 首次内容绘制 标记浏览器渲染来自 DOM 第一位内容的时间点,该内容可能是文本、图像、SVG 甚至 元素
const paint = performance.getEntriesByType('paint')
const FCP = paint[1].startTime
FMP 首次有效绘制
FMP(First Meaningful Paint) 首次有效绘制: 例如,在 YouTube 观看页面上,主视频就是主角元素.
图片可以没加载完成,但整体的骨架已经加载完成了。
1秒内完成FMP的概率超过80%,那就代表这个网站是一个性能较好的网站
let FMP = 0
const performanceObserverFMP = new PerformanceObserver((entryList, observer) => {
const entries = entryList.getEntries()
observer.disconnect()
FMP = entries[0].startTime
})
// 需要在元素中添加 elementtiming="meaningful"
performanceObserverFMP.observe({ entryTypes: ['element'] })
TTI 可交互时间
TTI (Time to Interactive) 可交互时间: DOM树构建完毕,可以绑定事件的时间
const { domInteractive, fetchStart } = performance.timing
const TTI = domInteractive - fetchStart
LCP 最大内容渲染
let LCP = 0
const performanceObserverLCP = new PerformanceObserver((entryList, observer) => {
const entries = entryList.getEntries()
observer.disconnect()
LCP = entries[entries.length - 1].startTime
})
performanceObserverLCP.observe({ entryTypes: ['largest-contentful-paint'] })
DCL
DCL (DomContentloaded): 当 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,无需等待样式表、图像和子框架的完成加载
const { domContentLoadedEventEnd, fetchStart } = performance.timing
const DCL = domContentLoadedEventEnd - fetchStart
L 全部加载完毕
L (on/Load), 当依赖的资源(图片、文件等), 全部加载完毕之后才会触发
const { domContentLoadedEventEnd, fetchStart } = performance.timing
const DCL = domContentLoadedEventEnd - fetchStart
FID 首次输入延迟
FID (First Input Delay) 首次输入延迟: 指标衡量的是从用户首次与您的网站进行交互(即当他们单击链接,点击按钮等)到浏览器实际能够访问之间的时间
let FID = 0
const performanceObserverFID = new PerformanceObserver((entryList, observer) => {
const entries = entryList.getEntries()
observer.disconnect()
FID = entries[0].processingStart - entries[0].startTime
})
performanceObserverFID.observe({ type: ['first-input'], buffered: true })
浏览器发起一个HTTP 请求过程
Chrome限制每个域名最多执行6个TCP连接。如果您一次请求十二个资源,前6个将开始,后6个将排队。一旦其中一个请求完成,队列中的第一个请求项目将开始其请求过程。
-
Queuing
(排队)排队时间 -
Stalled
(停滞)发送请求之前等待的时间 -
DNS lookup
(DNS查找), -
initial connection
(初始连接) -
SSL handshake
(SSL握手) -
Request sent
(请求发送)发出网络请求所花费的时间 -
Waiting
(等待)(到开始下载第一个字节的时间(TTFB))等待初始响应所花费的时间 -
Content Download
(内容下载)接收响应数据所花费的时间
TTFB就是等待第一个响应字节的时间,建议在200ms以下,以下情况可能会导致高TTFB(延迟):
- 客户端和服务器之间的网络条件差,
- 要么,服务器端程序响应很慢。
实验数据收集工具
Lihgthouse
chrome 浏览器,F12打开开发者工具,ctrl + shift + P
搜索Lighthouse可以调出此工具
参数含义
参考
首屏时间(FCP) VS 白屏时间(FP)
网站性能指标这么多,你到底选对了吗?
使用 RAIL 模型衡量性能
页面生命周期:DOMContentLoaded,load,beforeunload,unload
首屏时间与domContentLoaded触发时机的关系
Web 性能优化-首屏和白屏时间
控制台了解认知---network
初探performance-监控网页与程序性能
前端性能的几个基础指标
关于Web页面全链路性能优化指南
Navigation Timing
Using Navigation Timing APIs to understand your webpage
前端页面性能优化总结