前端性能优化分析

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

工具

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 来监听节点,如果节点的高度与大屏幕高度,则表示首屏已经渲染。
相关推荐
拉不动的猪17 分钟前
前端常见数组分析
前端·javascript·面试
小吕学编程34 分钟前
ES练习册
java·前端·elasticsearch
Asthenia041241 分钟前
Netty编解码器详解与实战
前端
袁煦丞1 小时前
每天省2小时!这个网盘神器让我告别云存储混乱(附内网穿透神操作)
前端·程序员·远程工作
一个专注写代码的程序媛2 小时前
vue组件间通信
前端·javascript·vue.js
一笑code2 小时前
美团社招一面
前端·javascript·vue.js
懒懒是个程序员2 小时前
layui时间范围
前端·javascript·layui
NoneCoder2 小时前
HTML响应式网页设计与跨平台适配
前端·html
凯哥19702 小时前
在 Uni-app 做的后台中使用 Howler.js 实现强大的音频播放功能
前端
烛阴3 小时前
面试必考!一招教你区分JavaScript静态函数和普通函数,快收藏!
前端·javascript