衡量指标
优化的意义
用户体验和转化率:网页流畅美观能够更吸引用户进入、停留(用户留存up)、完成购买流程,有利于增加收入,页面加载时间每增加1秒,转化率可能下降7%
DCL, L
DCL(DOMContentLoaded) 表示HTML加载完成事件, L(onLoad) 表示页面所有资源加载完成事件
白屏阶段、页面首帧(FCP)阶段、页面内容可见(LCP)阶段
CWV体系
网页性能三方面:从用户角度切入:内容展现快,视觉舒适。每个方面有一个关键指标,合称CWV
包括:LCP(最大内容渲染时间)、CLS(累计布局偏移指数)、INP(下次互动延迟时间) (INP 是一个较新的指标,自 2024 年 3 月 12 日起替换 FID 作为新的 CWV 之一)
前端:
秒开率:举个例子,假如通过性能监控数据发现,有15%的用户访问,需要花费至少 1s 的时间才能连接到我们的服务器(可以是SSR服务器,也可以是CDN),那么这些用户无论如何都不能秒开,那么此时,某页面秒开率的上限就是85%。 假如当前情况下,这个页面的秒开率已经达到了75%甚至更高,那么继续优化的边际收益会非常低,应该适可而止了。
重要指标
LCP(Core Web Vitals 指标): 可见最大图片或文本块的呈现时间(相对于用户首次导航到相应网页的时间)。 W3C性能组和谷歌研究:衡量页面主要内容的加载时间是查看最大元素呈现时间
逻辑:渲染过程中为最大元素分配LCP标识,直到用户与网页互动,将最近具有LCP标识的元素渲染时间作为LCP反馈
考虑元素:
计算LCP: 页面上最大的元素即绘制面积最大的元素,如果元素延伸到屏幕外,或者元素被裁切了一部分,被裁切的部分不算入在内,只有真正显示在屏幕里的才算数。
特殊处理:图片元素的面积计算方式稍微有点不同,可以通过 CSS 将图片扩大或缩小显示,也就是说,图片有两个面积:“渲染面积”与“真实面积”。在 LCP的计算中,图片的绘制面积将获取较小的数值。
过程:页面在加载过程中,是线性,元素逐个渲染到屏幕上的,而不是一瞬间全渲染到屏幕上,所以“渲染面积”最大的元素随时在发生变化。
指标获取:
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP candidate:', entry.startTime, entry);
}})
.observe({type: 'largest-contentful-paint', buffered: true});
指标优化 :
消除资源加载延迟:推荐做法是确保 LCP 资源与网页加载第一个资源同时启动。
消除元素渲染延迟:减少或内嵌阻止呈现的样式表,延迟或内嵌阻止呈现的 JavaScript
SSR 可以通过以下方式帮助优化 LCP:它可以让 HTML 源代码检测到您的资源,它可防止您的网页需要完成额外的 JavaScript 请求才能呈现。
缩短资源加载时间
详见:如何计算 LCP 指标--应用性能监控全链路版-火山引擎 (volcengine.com)
INP:到
2024年3月,首次输入延迟(FID)将被与下一次绘制的交互(INP)取代,成为交互性的Core Web Vitals。衡量的是用户交互(如点击或按键)后到下次在页面上看到视觉更新之间经过的时间什么是交互: 网页上的交互始于
用户输入。然后浏览器对此输入做出反应。这包括输入延迟、处理时间以及在下一次绘制之前的呈现延迟,直到新帧被呈现出来。![]()
INP延迟由三个组成部分构成:
- 输入延迟(
Input Delay):等待页面上的后台任务完成,阻止事件处理程序的运行。 - 处理时间(
Processing Time):运行JavaScript事件处理程序。 - 呈现延迟(
Presentation Dealy):重新计算页面布局并绘制页面内容。
INP涵盖了从鼠标、触摸或键盘输入开始,到浏览器渲染下一帧的整个时间段。在交互中持续时间最长的事件被选为交互的延迟。
INP 的计算借助 Event Timing API,通过观察事件处理程序的延迟来确定交互的响应时间
代替了FID,FID缺点:FID 只关注页面加载阶段的第一个交互,而 INP 考虑了页面的所有交互
优化: 识别减少输入延迟
FP(First Paint)(首次绘制): 首次绘制包括了任何用户自定义的背景绘制,它是将第一个像素点绘制到屏幕的时刻;
在性能统计指标中,从用户开始访问 Web 页面的时间点到 FP 的时间点这段时间可以被视为 白屏时间,也就是说在用户访问 Web 网页的过程中,FP 时间点之前,用户看到的都是没有任何内容的白色屏幕
FCP(First Content Paint)(首次内容绘制): 首次内容绘制是浏览器将第一个 DOM 渲染到屏幕的时间,可以是任何文本、图像、SVG 等的时间;
从用户开始访问 Web 页面的时间点到 FCP 的时间点这段时间可以被视为 无内容时间,也就是说在用户访问 Web 网页的过程中,FCP 时间点之前,用户看到的都是没有任何实际内容的屏幕,用户在这个阶段获取不到任何有用的信息。包含内容:"内容"指的是文本、图像(包括背景图像)、
<svg>元素或非白色的<canvas>元素。
二者区别: FP是当浏览器开始绘制内容到屏幕上的时候,只要在视觉上开始发生变化,无论是什么内容触发的视觉变化,在这一刻,这个时间点,叫做FP。
FCP指的是浏览器首次绘制来自DOM的内容。例如:文本,图片,SVG,canvas元素等,这个时间点叫FCP。
数据获取: PerformancePaintTiming 中包含当前 Web 页面的绘制性能打点信息,可通过 performance.getEntriesByType('paint') 方法获取, FP和 FCP 就在其中。
找到 name 为 first-paint 的对象,描述的即为 FP 的指标数据,其中 startTime 即为 FP 时间。
找到 name 为 first-contentful-paint 的对象,描述的即为 FCP 的指标数据,其中 startTime 即为 FCP 时间。
FMP(First Meaningful paint)(首次有意义绘制): 首次有意义绘制是页面可用性的量度标准;
FID(First Input Delay)(首次输入延迟): 用户首次和页面交互到页面响应交互的时间;
TBT(Total Blocking Time): 从 FCP 到TTI 之间的总时长
CLS (Cumulative Layout Shift) :从页面开始加载到其生命周期状态更改为隐藏期间发生的所有意外布局偏移的累计得分。
较低的 CLS 给用户呈现的效果是交互流程自然、没有延迟和卡顿。
常见场景:资源以异步方式加载,DOM 元素被动态添加到网页中的现有内容之前,尺寸未知的图片或视频、呈现的字体大于或小于其后备广告的尺寸,或者第三方广告或 widget 会自行调整自身大小。 代码
let clsValue = 0;
let clsEntries = [];
let sessionValue = 0;
let sessionEntries = [];
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Only count layout shifts without recent user input.
if (!entry.hadRecentInput) {
const firstSessionEntry = sessionEntries[0];
const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
// If the entry occurred less than 1 second after the previous entry and
// less than 5 seconds after the first entry in the session, include the
// entry in the current session. Otherwise, start a new session.
if (sessionValue
&& entry.startTime - lastSessionEntry.startTime < 1000
&& entry.startTime - firstSessionEntry.startTime < 5000) {
sessionValue += entry.value;
sessionEntries.push(entry);
} else {
sessionValue = entry.value;
sessionEntries = [entry];
}
// If the current session value is larger than the current CLS value
// update CLS and the entries contributing to it.
if (sessionValue > clsValue) {
clsValue = sessionValue;
clsEntries = sessionEntries;
// Log the updated value (and its entries) to the console.
console.log('CLS:', clsValue, clsEntries)
}
}
}}).observe({type: 'layout-shift', buffered: true});
import {onCLS} from 'web-vitals';
// Measure and log CLS in all situations
// where it needs to be reported.
onCLS(console.log);
TTFB(首字节时间) TTI (可交互时间):即从页面加载开始到页面处于完全可交互状态所花费的时间
- 页面已经显示有用内容。
- 页面上的可见元素关联的事件响应函数已经完成注册。
- 事件响应函数可以在事件发生后的 50ms 内开始执行。
TTI 值越小,代表用户可以更早地操作页面,用户体验就更好。 获取:直接通过服务端路由切换的同步跳转场景, 通过客户端路由跳转的 SPA 页面切换场景
Long Task :在浏览器主线程执行时间超过 50ms 的 Task。
静默窗口期:窗口所对应的时间内没有 Long Task,且进行中的网络请求数不超过 2 个。
工具
一般来说前端监控平台对性能指标的计算都是依赖于 web-vitals ,web-vitals 又是在 PerformanceObserver API 基础上封装的。
web-vitals 如果用web-vitals倒是可以直接获取性能指标的值
开发阶段,用lighthouse和WebPageTest。lighthouse统计本机的性能数据可以是首屏或者次屏,WebPageTest可以模拟具体的地区和设备通过API捕获首屏的性能数据,并且可以生成完整的网络请求时序图。
后端:
性能指标(吞吐量和响应速度 )
与吞吐量相关的衡量指标:
- QPS代表的是每秒的查询数量。
- TPS代表的是每秒事务的数量
- HPS代表的是每秒的HTTP请求数量。 明确优化事项:程序中存在数据库或者缓存的批量操作,虽然在数据的读取上,响应速度下降了,但优化的目标就是吞吐量,只要我们优化后系统的整体吞吐量明显上升了,那这也是提升了程序的性能。
响应速度有关:
- 平均响应时间
- 百分位数 : 圈定时间范围,将每次请求耗时加入有关列表,从小到大排序,取出特定百分位耗时。也就是TP值表示的含义就是:超过 N% 的请求都在 X 时间内返回。比如 TP90 = 50ms,意思是超过 90th 的请求,都在 50ms 内返回。百分位数这个指标也是很重要的,它反映的是应用接口的整体响应情况。对高百分位的值要求越高,对系统响应能力的稳定性要求越高。
并发量:系统能够同时处理的请求数量,反映的是系统的负载能力。对高并发系统进行优化的时候,往往也会在并发量上进行调优
秒开率:如果一个前端网页或者APP能够在1秒内很平滑的打开,尤其是首页的加载。此时,用户就会感到前端网页或者APP使用起来很顺畅,如果超过3秒甚至更长的时间,用户就有可能会直接退出前端网页或者APP不再使用。
正确性:无论我们以何种方式,何种手段对应用进行优化,优化后的交互数据结果必须是正确的。
不是一味的优化吞吐量和优化响应速度,而是在吞吐量和响应速度之间找到一个平衡点,使用有限的服务器资源来更好的提升用户体验。
应用体系(不能为了优化而优化)
- 指标设定&性能标准:选择什么样的指标作为风向标,优化的目标和程度
- 收益评估:关联产品目标进行收益评估,优化是服务于产品,提升用户体验。
- 诊断清单:接入到性能监控预警平台,根据性能标准给出诊断清单,方便我们进行后续的改进和优化
- 优化手段
- 性能立项:和产品与后端打配合
- 性能实践:上线,效果评估,结合场景沉淀成文档代码
性能监控平台的意义:
建立一个准确、及时、有效的前端性能监控系统,不仅可以量化当前页面的性能水平,还可以为优化方案的效果提供数据支持,此外,还可以在页面性能下滑时提供报警服务,提醒开发人员改善页面性能。
腾讯云流程:
优化场景示例
确立项目背景
从技术的角度去思考如何提升用户体验
统计口径
首先确立量化性能的相关指标,便于分析问题,确立首要任务。 进行看板分析:Chrome Performance 火焰图
这几个红色区域长任务,我们知道主线程一次只能处理一个任务,所以这会导致浏览器在主线程上阻塞一段时间,也是造成页面卡顿的主要原因。按照对应项目去分析这些任务
全链路分析
项目现状
优化方案
具体优化: 首屏资源优化
-
入口 JS 资源文件 Size 优化
- 严重影响了页面整体加载性能,可以通过构建体积优化,主要思路就是代码分割拆包,静态资源上传 CDN,脚本代码压缩等方式处理
-
接口缓存、调用时序治理
- 针对用户信息、菜单信息等不常变动的接口可以采用相关缓存策略,减少首屏等待的时间
- 部分优先级不高的接口可以延迟调用,异步加载 减少首屏需要加载的资源数量和大小,并尽快加载必要的资源 渲染优先级优化
最后为了减少 LCP 的等待时间,我们将页面左侧菜单栏做一个懒加载处理,初始化仅展示一级目录菜单,既考虑了首屏视觉效果,也间接将子应用加载的时间点提前。
效果回收
总结展望
京东云团队(由js大量计算,ui阻塞,卡顿掉帧,出现页面卡死)
【万字长文】前端性能优化实践 | 京东云技术团队_前端工程体验优化实战-CSDN博客 浏览器具有GUI渲染线程与JS引擎线程,互斥。当js引擎执行会导致gui引擎挂起,GUI更新会被保存在一个队列中,等到JS引擎空闲时,立即被执行。
GUI渲染线程: 负责渲染浏览器页面,解析HTML、CSS,构建DOM树、构建CSSOM树、构建渲染树和绘制页面;当界面需要重绘或由于某种操作引发回流时,该线程就会执行
JS引擎线程: JS引擎线程也称为JS内核,负责处理Javascript脚本程序,解析Javascript脚本,运行代码;
- 背景: 测试流水线开发过程中,为了满足用户操作方便,从节点中提取不同的指标来作为查询条件的指标来源和数据来源; 因此用户的每次操作都会进行重新计算,引起回流; 由于前端组件父子嵌套层级很多,在数据过多的时候也会形成页面假死的状态。
使用performance录制
FPS上方显示红色条的时候,意味着帧率特别低,用户体验特别不好。一般来说,绿色条越高,FPS越高。 分析性能图标第一眼看FPS;性能面板底部,图形图表的色彩越多,意味着CPU性能已经达到极限。当我们看到CPU长时间处于最大值状态,就需要考虑怎样去优化
实践指南-前端性能提升 270% | 京东云技术团队 - 掘金 (juejin.cn)
提升产品的性能和弱网情况下的体验: 网易云课堂 Service Worker 运用与实践 (qq.com)