前端性能优化分析

前面谈到了性能优化, 那如何评判我们的性能优化的效果,以及检测哪些地方做的不够?

工具

Lighthouse

lighthouse 是一个用于诊断网页的工具,包括 性能、无障碍、渐进式、SEO 等方面,通过得分的方式来报告网页的质量。

使用方法:

  • Dev Tools : 直接在 Dev Tools 中 lighthouse panel 勾选 Mode 、 Device 、Categories 之后点击 Analyze page load 即可
  • lighthouse 扩展程序
  • npm 包
xml 复制代码
npm install -g lighthouse
lighthouse <url>

Performance Panel

chrome Dev Tools 中的 Performance panel 是一个专门检测性能的面板。里面有非常详细的数据,可以查看到性能相关的各个方面的数据

访问xw.qq.com之后,通过Performance面板跑的数据:如下

最上面是 CPU , heap 数据, 下面是其他的指标

  • Network : 可以看到资源的加载顺序以及其耗时
  • Frames : 页面帧变化截图
  • Main : 程序主进程(重要),可以用于分析 长任务
  • Timings: DCL(DocumentContentLoad event) FCP LCP 等指标

Performance Api

Performance Api 是一组用于衡量 web 应用性能的标准。 包含了 DOM 加载,渲染, 其他的资源加载过程 等指标,还可以自定义指标。

页面加载的过程分为多个阶段,如下

css 复制代码
    window.performance.timing: 
    {
        "connectStart": 1711121440358,
        "navigationStart": 1711121440354,
        "secureConnectionStart": 0,
        "fetchStart": 1711121440358,
        "domContentLoadedEventStart": 1711121440526,
        "responseStart": 1711121440422,
        "domInteractive": 1711121440526,
        "domainLookupEnd": 1711121440358,
        "responseEnd": 1711121440428,
        "redirectStart": 0,
        "requestStart": 1711121440365,
        "unloadEventEnd": 1711121440425,
        "unloadEventStart": 1711121440425,
        "domLoading": 1711121440427,
        "domComplete": 1711121440592,
        "domainLookupStart": 1711121440358,
        "loadEventStart": 1711121440592,
        "domContentLoadedEventEnd": 1711121440526,
        "loadEventEnd": 1711121440594,
        "redirectEnd": 0,
        "connectEnd": 1711121440358
    }

页面加载完了,window.performance.timing对下中会包含上图阶段对应的时间戳值,我们可以通过某些值的计算得出一些指标数据,如白屏时间,首屏时间等。

performance.getEntries() 包含了在页面加载过程中检测到所有指标, 包含资源加载, FP FCP 等多个指标。 可以通过过滤entryType来分析具体的指标数据。

yaml 复制代码
VisibilityStateEntry {name: 'visible', entryType: 'visibility-state', startTime: 0, duration: 0}
PerformanceResourceTiming {initiatorType: 'link', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'link', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'link', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'script', nextHopProtocol: 'h2', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'script', nextHopProtocol: 'h2', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'link', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'link', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'link', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'script', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'img', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'img', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'css', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'css', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'css', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformancePaintTiming {name: 'first-paint', entryType: 'paint', startTime: 2446.5999999940395, duration: 0}
PerformancePaintTiming {name: 'first-contentful-paint', entryType: 'paint', startTime: 2446.5999999940395, duration: 0}
PerformanceResourceTiming {initiatorType: 'iframe', nextHopProtocol: '', deliveryType: '', workerStart: 0, redirectStart: 0, ...}
PerformanceResourceTiming {initiatorType: 'other', nextHopProtocol: 'h2', deliveryType: 'cache', workerStart: 0, redirectStart: 0, ...}

关键指标

FPS : 页面刷新帧率

页面卡顿 ? 判断页面是否卡顿,就是计算页面 FPS , 60 左右是一个比较优的帧率,就是大约 16.5ms刷新一次页面。

如何计算 FPS ? requestAnimationFrame 是跟随着帧率执行代码,计算 1 秒 执行的次数就可以计算出帧率

如何减少卡顿 ? 减少卡顿就是避免长时间占用主进程,给予刷新页面留时间。由于 JS 的执行是单线程,如果长时间占用主线程,那么刷新页面,响应用户,就会滞后,进而导致卡顿。 解决方案:就是长任务拆解,将长任务拆解成多个短任务,将短任务分别置于任务循环中,在下个任务循环时执行。那么主线程就用空档来刷新页面,响应用户。

如何分析?

实际过程中可以用 Chrome Dev Tool 的 Performance Panel 中的 Main 来分析长任务。

也可以通过 performance.getEntries() 过滤 entryType = 'longtask'来分析

白屏时间 & 首屏时间

  • 白屏时间: 请求页面到开始渲染时间, 可以用performance Api
ini 复制代码
const whiteScreenTime = performance.timing.responseStart - performance.timing.navigationStart;
  • 首屏时间: 完全渲染第一屏的时间,第一屏会根据具体业务变化而变化,这里不是个固定值。一般可以有下面几种方式
    • DCL : domcumentContentLoad 事件触发时间 performance.timing.domContentLoadedEventEnd
    • LCP : FCP 是首次绘制的时间, LCP (largest-contentful-paint) 可以更准备的描述首屏时间
    • 监控节点高度: 使用 MutationObserver 来监听节点,如果节点的高度与大屏幕高度,则表示首屏已经渲染。
相关推荐
加班是不可能的,除非双倍日工资2 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi3 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip3 小时前
vite和webpack打包结构控制
前端·javascript
excel4 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国4 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼4 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy4 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT4 小时前
promise & async await总结
前端
Jerry说前后端4 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化
画个太阳作晴天4 小时前
A12预装app
linux·服务器·前端