方法和指标和工具✅
如何做性能优化的?
答案
-
评估阶段 (Assess) 确定关键指标体系, 注意评估的指标和方式需要结合真实的业务场景,分析关键链路,具体可以参考 以用户为中心的效果指标 常见的评估指标如下
指标类型 核心指标 业务价值 优先级 加载性能 LCP、FCP 首次体验 P0 交互性能 FID/INP、TTI 用户操作响应 P0 视觉稳定性 CLS 视觉体验 P1 基础性能 TTFB、资源加载时间 技术基础 P2 -
收集阶段 (Collect) 通过埋点等手段进行用户端性能数据的收集,常用的工具包括 web-vitals 、sentry 等。
-
分析阶段 (Analyze) 通过真实的用户数据进行性能分析,识别性能瓶颈。
-
验证阶段 (Validate), 采用 AB 验证,或者实验手段验证效果,重复上述流程进行持续优化。
-
标准化和自动化,将性能优化的流程和指标标准化,形成自动化的监控和预警机制。重复上述 1-5 的流程
延伸阅读
- Learn Performance - Chrome 性能学习教程
- RAIL Performance Model - Google RAIL 性能模型
- User-Centric Performance Metrics - 以用户为中心的性能指标
- Performance Budgets - 性能预算制定指南
常用性能指标
答案
指标名称 | 描述 |
---|---|
TTFB(Time to First Byte) | 首字节时间,指浏览器发起请求到接收到第一个字节的时间。 |
FCP(First Contentful Paint) | 首次内容绘制,指浏览器开始渲染页面内容的时间点。 |
LCP(Largest Contentful Paint) | 最大内容绘制,指页面上最大的可见内容元素被渲染的时间点。 |
INP(Interaction to Next Paint) | 交互到下一个绘制,指用户交互后页面更新的时间点。 |
FID(First Input Delay) | 首次输入延迟,指用户首次与页面交互到浏览器实际开始处理交互事件的时间间隔。 |
TTI(Time to Interactive) | 可交互时间,指页面完全加载并且可以响应用户交互的时间点。 |
TBT(Total Blocking Time) | 总阻塞时间,指在页面加载过程中,主线程被阻塞的总时间。 |
CLS(Cumulative Layout Shift) | 累积布局偏移,指页面内容在加载 |
性能指标并不是一成不变的,它们需要根据具体的业务场景进行定义和调整。比如在电商网站中,LCP 可能更关注商品图片的加载时间,而在新闻网站中,FCP 可能更关注文章内容的加载时间。此外还有诸如卡顿率、秒开率等指标。
延伸阅读
有哪些前端性能分析工具
答案
工具类型 | 工具名称 | 主要功能 | 适用场景 |
---|---|---|---|
浏览器开发者工具 | Chrome DevTools | Performance面板分析CPU使用率、内存占用、网络请求;Network面板查看请求耗时;Lighthouse审计性能、可访问性 | 开发调试、实时性能分析 |
Firefox Developer Tools | 性能分析、网络监测 | 开发调试 | |
在线性能监测平台 | WebPageTest | 多地点性能测试,提供FCP、LCP、FID等指标,生成可视化报告 | 全面性能测试、定期监控 |
Pingdom Tools | 测试网站性能和可用性,提供优化建议 | 快速性能检查 | |
性能监控工具 | Google Analytics | 页面加载时间、用户行为数据 | 用户体验分析 |
New Relic Browser | 全面前端性能监控,实时跟踪用户交互 | 生产环境监控 | |
代码分析工具 | Lighthouse CI | 集成到CI流程,自动化性能审计 | 持续集成 |
PageSpeed Insights API | API方式获取性能分析结果 | 自动化监控 | |
专业分析工具 | web-vitals | 收集Web Vitals指标 | 核心指标监控 |
sentry | 性能监控和错误追踪 | 全栈监控 |
分类说明
- 开发阶段 主要使用浏览器开发者工具进行实时调试和分析
- 测试阶段 使用在线监测平台进行全面的性能测试
- 生产阶段 部署性能监控工具进行持续监控和告警
- 自动化 集成代码分析工具到CI/CD流程中
建议采用多层次的性能分析策略:开发时用Chrome DevTools,测试时用WebPageTest,生产环境部署专门的监控工具如Sentry,并在CI中集成Lighthouse进行自动化检查。
延伸阅读
- Chrome DevTools Performance - Chrome性能分析官方文档
- WebPageTest - 在线性能测试平台
- Lighthouse - Google开源性能审计工具
- web-vitals - Google Web Vitals测量库
说一下 Performance API
答案
Performance API 是浏览器提供的性能测量接口,用于监控和分析网页性能。
核心接口 | 功能 | 代码示例 |
---|---|---|
performance.timing | 页面导航时间点 | timing.loadEventEnd - timing.navigationStart |
performance.now() | 高精度时间戳 | const start = performance.now() |
performance.getEntries() | 获取性能条目 | performance.getEntriesByType('resource') |
PerformanceObserver | 实时性能监听 | observer.observe({ entryTypes: ['longtask'] }) |
主要应用场景
场景 | 实现方式 | 关键指标 |
---|---|---|
页面加载监测 | performance.timing | 首屏时间、白屏时间 |
资源加载分析 | getEntriesByType('resource') | 资源耗时、加载瀑布 |
用户交互响应 | performance.now() | 点击响应时间 |
Long Task 监控 | PerformanceObserver | 阻塞时间、卡顿检测 |
自定义测量 | mark() + measure() | 业务流程耗时 |
核心代码示例
// 监听长任务
const observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
console.log(`Long task: ${entry.duration}ms`)
})
})
observer.observe({ entryTypes: ['longtask'] })
// 自定义性能标记
performance.mark('operation-start')
// 执行操作
performance.mark('operation-end')
performance.measure('operation', 'operation-start', 'operation-end')
实际开发要点
- 优先使用 PerformanceObserver 而非轮询,减少性能开销
performance.timing
已废弃,新项目使用 Navigation Timing Level 2- 跨域资源需服务器设置
Timing-Allow-Origin
头 - 及时清理性能条目缓冲区避免内存泄漏
参考资料
说一下什么是 FCP?
答案
首次内容渲染 (FCP) 衡量从用户首次导航到网页到网页任何一部分内容呈现在屏幕上的时间。对于此指标,“内容”是指文本、图片(包括背景图片)、<svg>
元素或非白色 <canvas>
元素。
网站应尽量将首次有意义的绘制时间控制在 1.8 秒或更短的时间。为确保大多数用户都能达到此目标值,一个合适的衡量阈值是网页加载时间的第 75 个百分位数,并按移动设备和桌面设备进行细分。Lighthouse 将 FCP 视为一个重要的性能指标,并将其纳入其性能评分中。具体详见 FCP
FCP 的测量可以采用
延伸阅读
- First Contentful Paint (FCP) 首次内容绘制
- TFMP Google 的性能测量文档
- TTFMP UBA Google 的性能测试文档
FP、FCP 有什么区别和白屏时间有什么关系?
答案
指标 | 全称 | 定义 | 触发条件 |
---|---|---|---|
FP | First Paint | 首次绘制 | 浏览器首次绘制任何像素到屏幕上 |
FCP | First Contentful Paint | 首次内容绘制 | 浏览器首次绘制来自DOM的内容(文本、图片、SVG等) |
白屏时间 | White Screen Time | 白屏持续时间 | 从页面开始加载到首次有内容显示 |
时间关系图示
导航开始 → 白屏阶段 → FP → FCP → 页面可交互
| | | | |
| | | | └─ 用户可以看到有意义的内容
| | | └─ 首次内容绘制
| | └─ 首次绘制(可能是背景色、边框等)
| └─ 用户看到的是白屏
└─ performance.timing.navigationStart
注意白屏时间并不是一个严格的技术指标,而是用户体验的感知。从简化处理方面可以近似认为 FP 时间就是白屏时间,但是从用户视角可能没加载出来具体内容也被认为白屏,此时需要根据具体的场景去定义白屏时间的计算方式。
代码测量示例
// 监听 paint 事件
const observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
if (entry.name === 'first-paint') {
console.log(`FP: ${entry.startTime}ms`)
}
if (entry.name === 'first-contentful-paint') {
console.log(`FCP: ${entry.startTime}ms`)
console.log(`白屏时间: ${entry.startTime}ms`)
}
})
})
observer.observe({ entryTypes: ['paint'] })
在优化时,FCP 比 FP 更重要,因为它代表用户真正看到内容的时刻。通过优化关键渲染路径可以同时改善这两个指标。
延伸阅读
- First Paint (FP) - 首次绘制详解
- First Contentful Paint (FCP) - 首次内容绘制指南
- Paint Timing API - 绘制时间测量规范
如何统计资源加载耗时?
答案
资源加载耗时统计通过 Performance API 的 Resource Timing 接口实现,可以监控所有静态资源的加载性能。
核心监控方法
方法 | 功能 |
---|---|
performance.getEntriesByType('navigation') | 用于衡量 HTML 文档请求(即导航请求)的速度 |
performance.getEntriesByType('resource') | 例如 CSS、JavaScript、图片和其他资源类型 |
fetch/xhr | 手动统计网络请求耗时 |
对于跨域资源,如果服务器未设置 Timing-Allow-Origin
头,则只能获取到基本的时间信息,详细的网络时间(如DNS、TCP连接时间)将被屏蔽。
延伸阅读
如何监控卡顿?
答案
参考 google 设备刷新率说明 如果单帧的渲染时间超过设备的刷新率(例如 60Hz 刷新率对应每帧约 16.67ms)则定义为卡顿。
基于帧率的概念,可以采用 requestAnimationFrame
来监控卡顿。示例代码如下
let lastFrameTime = 0
let frameCount = 0
let jankCount = 0
function monitorFrame () {
const currentTime = performance.now()
const deltaTime = currentTime - lastFrameTime
if (deltaTime > 16.67) { // 假设60Hz刷新率
jankCount++
console.warn(`Jank detected! Frame took ${deltaTime.toFixed(2)}ms`)
}
frameCount++
lastFrameTime = currentTime
requestAnimationFrame(monitorFrame)
// 可以在这里输出当前帧率和卡顿次数
console.log('Frame Rate: ', (1000 / deltaTime).toFixed(2), 'FPS')
console.log('Jank Count: ', jankCount)
}
monitorFrame()
注意这里只是针对刷新率是 60FPS 的设备,对于诸如 90Hz、120Hz 等高刷新率设备,需要根据实际的刷新率来调整判断卡顿的阈值。此外在实际的应用中还要考虑采样频率等问题、平滑数据等问题。
延伸阅读
- Jank卡顿及stutter卡顿率说明 腾讯 perfdog 对卡顿相关定义的说明
如何统计页面的 long task ?
答案
Long Task 是指在主线程上执行超过 50 毫秒的任务,chrome 会在性能面板对长任务打上红色标记
采用 PerformanceObserver, 通过 observer.observe({ entryTypes: ["longtask"] });
监听长任务。
注意 chrome 只会把在主线程持续执行时间大于 50ms 的任务统计为长任务,可以将示例中的 LongTaskInterval = 49 来验证此逻辑
对于长任务的优化通常通过将任务拆分为更小的子任务来实现,以减少单个任务的执行时间,从而避免长任务的出现。具体策略可以参考 优化耗时较长的任务
延伸阅读
如何实现自定义指标采集?
答案
自定义指标采集通过 Performance API 实现业务链路性能监控,主要使用 performance.mark()
和 performance.measure()
进行精确测量。
方法 | 功能 | 使用场景 | 数据获取 |
---|---|---|---|
performance.mark() | 创建时间戳标记 | 标记关键节点 | performance.getEntriesByName() |
performance.measure() | 测量两点间耗时 | 计算阶段耗时 | performance.getEntriesByName() |
performance.now() | 获取高精度时间戳 | 手动计时 | 直接返回数值 |
参考示例
实际开发要点
- 及时清理性能条目避免内存泄漏,使用
performance.clearMarks()
和performance.clearMeasures()
- 标记名称应具有唯一性,建议使用命名空间前缀
- 高频操作谨慎使用,避免性能条目缓冲区溢出
- 结合 PerformanceObserver 实现自动化数据收集
自定义指标采集特别适合 SPA 应用的路由切换、组件渲染、API 请求等关键业务流程的性能监控。
延伸阅读
- User Timing API - 用户自定义性能测量规范
- Performance Timeline - 性能时间线标准
- MDN: Performance.mark() - 性能标记方法详解