用户在访问网页时,网页的性能好坏给用户带来了什么,或者说用户需要的高性能是什么样的,又或者说是用户能感知到的性能是什么?
# | 用户关注的内容 | 意义 |
---|---|---|
1 | 是否正在发生? | 当我输入 URL 并回车时,导航到底有没有发生呢?背后的服务器是不是有响应呢? |
2 | 是否有用? | 我访问页面时,页面是否快速展现了用户最关注的内容或者是展现了产品最需要了解的内容? |
3 | 是否可用? | 当页面第一次展现出可交互的元素时,用户的使用是否是有效的? |
4 | 是否令人愉悦的? | 用户与页面的交互是否流程、自然?不会出现延迟和卡顿? |
根据用户感知的性能,我们可以初步确认前端 Web,H5 性能测试的维度、方向是以下内容:
# | 维度 | 含义 | 用户关注的内容 |
---|---|---|---|
1 | 感知加速度(Perceived load speed) | 页面在屏幕上加载并渲染出所有视觉元素的速度 | 是否正在发生? 是否有用? |
2 | 加载响应度(Load responsiveness ) | 为了使组件对用户交互作出快速响应,页面加载和执行任何所需 JavaScript 代码的速度。 | 是否可用? |
3 | 运行响应度(Runtime responsiveness) | 页面在加载后,对用户交互的响应速度 | 是否令人愉悦? |
4 | 视觉稳定性(Visual stability) | 页面上的元素是否会出现让用户感到意外的偏移,并对用户交互造成潜在的干扰? | 是否有用? 是否可用? 是否令人愉悦? |
5 | 平滑度(Smoothness) | 过渡和动画在页面状态切换的过程中是否具有稳定的帧速率和顺滑的流动性? | 是否可用? 是否令人愉悦? |
根据用户对性能的感知和性能的测试维度,我们可以确认前端 Web、H5 性能测试的重要指标:
# | 指标 | 含义 | 优先级 | 测试维度 |
---|---|---|---|---|
1 | FCP | First Contentful Panit:首次内容绘制 测量页面从开始加载到页面内容的任何部分在屏幕上完成渲染的时间。 |
P0 | 感知加速度 |
2 | LCP | Largest Contentful Paint:首次最大内容绘制 测量页面从开始加载到最大文本块或图像元素在屏幕上完成渲染的时间 |
P0 | 感知加速度 |
3 | FID | First Input Delay:首次输入延时 测量从用户第一次与您的网站交互(例如当他们单击链接、点按按钮或使用由 JavaScript 驱动的自定义控件)直到浏览器实际能够对交互做出响应所经过的时间。 |
P3 | 加载响应度 |
4 | TTI | Time To Interactive:可交互时间 测量页面从开始加载到视觉上完成渲染、初始脚本(如果有的话)完成加载,并能够快速、可靠地响应用户输入所需的时间。 |
P1 | 加载响应度、运行响应度 |
5 | TBT | Total Blocking Time 总阻塞时间 测量 FCP 与 TTI 之间的总时间,这期间,主线程被阻塞的时间过长,无法作出输入响应。 |
P1 | 加载响应度、运行响应度 |
6 | CLS | Cumulative Layout Shift 累积布局偏移 测量页面在开始加载和其生命周期状态变为隐藏期间发生的所有意外布局偏移的累积分数。 |
P2 | 视觉稳定性、平滑度 |
在前端 Web、H5 的性能测试过程中,只感觉性能指标进行测试时不够的,还需要确保功能的准确性和兼容性
# | 指标 | 含义 | 测试维度 |
---|---|---|---|
1 | AF | Accurate Function 功能准确 测量页面全部加载完成后,当前页面的展现和交互功能是否符合产品设计和交互逻辑 |
|
2 | CF | Compatible Function 功能兼容 测量同一个页面在不同环境中(例如:网络环境,软件环境、硬件环境)中的功能、性能表现 |
综上所述,我们收敛出前端性能测试的质量模型
首次内容绘制 (FCP) 是测量感知加载速度的一个以用户为中心的重要指标,因为该项指标会在用户首次在屏幕上看到任何内容时,在页面加载时间轴中标记出相应的点,迅捷的 FCP 有助于让用户确信某些事情正在进行。
测量页面从开始加载到页面内容的任何部分在屏幕上完成渲染的时间。
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntriesByName('first-contentful-paint')) {
console.log('FCP candidate:', entry.startTime, entry);
}
}).observe({type: 'paint', buffered: true});
最大内容绘制 (LCP) 是测量感知加载速度的一个以用户为中心的重要指标,因为该项指标会在页面的主要内容基本加载完成时,在页面加载时间轴中标记出相应的点,迅捷的 LCP 有助于让用户确信页面是有效的。
测量页面首次开始加载的时间点来报告可视区域内可见的最大图像或文本块完成渲染的相对时间。
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntriesByName('first-contentful-paint')) {
console.log('FCP candidate:', entry.startTime, entry);
}
}).observe({type: 'paint', buffered: true});
首次输入延迟 (FID) 是测量加载响应度的一个以用户为中心的重要指标,因为该项指标将用户尝试与无响应页面进行交互时的体验进行了量化,低 FID 有助于让用户确信页面是有效的。
测量从用户第一次与页面交互(例如当他们单击链接、点按按钮或使用由 JavaScript 驱动的自定义控件)直到浏览器对交互作出响应,并实际能够开始处理事件处理程序所经过的时间。
A 时间点:页面已经加载出了可交互的元素;
B 时间点:可交互的元素背后的 JS 代码开始在主线程中进行处理;
C 时间点:用户与可交互的元素进行交互;
D 时间点:可交互元素背后的 JS 代码处理完成;
所以当用户在时间点 C 的时候与元素进行交互时,并不能第一时间得到交互的反馈,需要等到 D 时间后才会得到交互的反馈,D-C = FID
在整个页面的加载渲染过程中,让用户第一时间发现"立即抢购"按钮并产生交互(点击时),便产生了 FID 的时间。
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
const delay = entry.processingStart - entry.startTime;
console.log('FID candidate:', delay, entry);
}
}).observe({type: 'first-input', buffered: true});
测量页面从开始加载到视觉上完成渲染、初始脚本(如果有的话)完成加载,并能够快速、可靠地响应用户输入所需的时间。
测量页面从开始加载到主要子资源完成渲染,并能够快速、可靠地响应用户输入所需的时间。
测量 FCP 与 TTI 之间的总时间,这期间,主线程被阻塞的时间过长,无法作出输入响应。
总阻塞时间 (TBT) 指标测量 FCP 与 TTI 之间的总阻塞时间,这期间,主线程被阻塞的时间过长,无法作出输入响应。
TBT 是 TTI 的一个出色的配套指标,因为 TBT 有助于量化在页面交互性变为可靠前,不可交互程度的严重性
浏览器页面加载主线程中存在 5 个任务其中 3 个超过 50ms
虽然在主线程上运行任务的总时间为 560 毫秒,但其中只有 345 毫秒被视为阻塞时间。
T1 = TTI-FCP
TBT = T1 范围内的 long task 时间总和-TI 范围内的 long task 个数 *50ms
为了提供良好的用户体验,网站在普通移动硬件上进行测试时,应该努力将总阻塞时间控制在 300 毫秒以内。
测量整个页面生命周期内发生的所有意外布局偏移中最大一连串的布局偏移分数。
只要可视区域中可见元素的起始位置在两帧之间发生了变更,这样的元素认定为不稳定元素。
只有当元素的起始位置发生变更时才算作布局偏移,新元素添加到 DOM 中或者改变元素的大小则不算布局偏移。
第一帧中文本元素占比 50%,在第二帧中文本元素其实未知下移 20%,文本元素的总可占比变为 70%
距离分数指的是任何不稳定元素在一帧中位移的最大距离(水平或垂直)除以可视区域的最大尺寸维度(宽度或高度,以较大者为准)。
第二帧中位移距离在高度中占比 20%
布局偏移分数=影响分数 0.7* 距离分数 0.2 = 0.14
let clsValue = 0;
let clsEntries = [];
let sessionValue = 0;
let sessionEntries = [];
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// 只将不带有最近用户输入标志的布局偏移计算在内。
if (!entry.hadRecentInput) {
const firstSessionEntry = sessionEntries[0];
const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
// 如果条目与上一条目的相隔时间小于 1 秒且
// 与会话中第一个条目的相隔时间小于 5 秒,那么将条目
// 包含在当前会话中。否则,开始一个新会话。
if (sessionValue &&
entry.startTime - lastSessionEntry.startTime < 1000 &&
entry.startTime - firstSessionEntry.startTime < 5000) {
sessionValue += entry.value;
sessionEntries.push(entry);
} else {
sessionValue = entry.value;
sessionEntries = [entry];
}
// 如果当前会话值大于当前 CLS 值,
// 那么更新 CLS 及其相关条目。
if (sessionValue > clsValue) {
clsValue = sessionValue;
clsEntries = sessionEntries;
// 将更新值(及其条目)记录在控制台中。
console.log('CLS:', clsValue, clsEntries)
}
}
}
}).observe({type: 'layout-shift', buffered: true});
可以使用灯台工具测试 CLS
环境 | 内容 |
---|---|
网络 | 4g,5g,wifi |
系统 | android,iOS |
缓存 | 首开,二开 |
状态 | 登陆,未登录 |
平台 | 微信、小程序、浏览器 |
对售卖流程中的某环节进行性能专项人工测试,各环境场景下各前端性能指标提取!
注意,我们建议:
对核心的重要的前端业务的某环节进行持续、周期性能提取,分析,报告。
注意,我们建议:
QA 需要判断出是否需要做性能专项测试。如果需要和产品确认性能的要求。
QA 需要将产品的性能要求翻译成具体的性能指标并和开发确认。
QA 与开发确认性能埋点指标范围、上报信息、埋点可提取性。
QA 需要梳理当前性能专项测试对应的场景,工具、方法,设备,报告。
QA 明确已经确认的性能专项指标、场景、工具、方法、设备、报告的有效性。
QA 进行性能专项指标的提取、汇总。
QA 测试过程中发现性能问题时,需要及时反馈、终止性能测试,待性能问题修复后继续进行测试。
QA 对性能监控依赖的性能埋点的有效性进行确认。
性能监控依赖的性能埋点发生新增或变化时,不需要进行性能专项测试,需要做到的是在测试阶段功能测试后确认性能埋点的有效性。
性能监控≠性能专项测试
我们希望支撑性能监控的性能埋点能够体现出以下信息:
1、页面名称
2、业务流程名称
3、页面版本
4、环境:网络、平台、系统、是否发生登陆等
通过以上信息在性能监控中反应出特定流程下特定页面的特定版本的各环境场景的性能表现。