前端性能检测指南

492 阅读14分钟

主要针对面试做的准备,没有过多的图片和代码。相关API 的使用可以在 MDN 查看

1. 性能监测指标

  • Load Event

window.onload 事件 。当资源都加载完成后,触发。

load 仅是资源都下载完成,但页面不一定有渲染。

可能内容很多,还在解析过程中。

  • DOMContentLoaded ( DML

DOM 解析完成。DOM 解析完成,资源可能下载完成,也可以还在下载。

以上两个都是针对资源的。并不针对渲染。特别是你的页面资源放置的位置不同,内容渲染内容大小有区别的时候,就无法准确计算是否页面已经开始渲染了。

  • FP ( first paint)

渲染出第一个像素点时的时间点。

如果 HTML 都在 CSS 之后,那么HTML 和 CSS 都解析完成了。开始渲染。

此时的时间基本上可以代表首屏时间了

如果前面的 CSS 已经加载完成。那么则是部分的 HTML 已经解析完成。

此时,但之后可能还有 CSS 或者 JS 会堵塞渲染。FP只能代表开始渲染。

另外图片也是一个影响元素,即内容渲染完了,图片可以还没有下载完。

这个时候就可能需要考虑 load 触发的时间点

  • FCP ( First contentful Paint )

contentful 是指文本,图片 ,非空白 Canvas 或 SVG 的时间

而无内容的标签,即使有颜色,大小等,是不会触发 FCP 的。

  • FMP ( First Meaningful Paint )

首次有意义的内容的渲染的时间点。这个因为内容的不同,标准也不同。

zhuanlan.zhihu.com/p/81329849

  • LCP ( largest contentful paint )

指得是渲染中,最大得,有意义内容得渲染。

即渲染面积最大得文本,或者是图片,或者是 canvas 。

如果图片下载的时间比较久,则不被考虑

  • TTI(Time to Interactive)

交互时间 (TTI) 是一种非标准化的 Web 性能“进度”指标,是 FCP 后的 ,最后一个长任务完成的时间点,随后是 5 秒的网络和主线程不活动。(也有说,不超过两个 GET 请求)

如果没有长任务,则于 FCP 相同。

  • TBT (Total Blocking Time)

阻塞总时间,记录在 FCP 到 TTI 之间所有长任务的阻塞时间总和

  • FID (frist input delay)

首次输入延迟 (FID) 测量从用户首次与您的网站交互(即当他们单击链接、点击按钮或使用自定义的、JavaScript 驱动的控件时)到浏览器实际能够响应该交互的时间。

它是网页上第一次用户交互与浏览器对该交互的响应之间的时间长度(以毫秒为单位)。滚动和缩放不包括在此指标中。

  • SI ( speed index)

速度指数 (SI) 是一种页面加载性能指标,可显示页面内容的明显填充速度。这是显示页面可见部分的平均时间。以毫秒为单位表示,取决于视区的大小,分数越低越好。

  • CLS (Cumulative Layout Shift)

是对在页面的整个生命周期中发生的每一次意外布局变化的最大布局变化得分的度量,布局变化得分越小证明你的页面越稳定。

听起来有点复杂,这里做一个简单的解释:

不稳定元素:一个非用户操作但发生较大偏移的可见元素称为不稳定元素。

布局变化得分:元素从原始位置偏移到当前位置影响的页面比例 * 元素偏移距离比例

zhuanlan.zhihu.com/p/195731901

  • FPS (frames per second)

刷新率。浏览器的标准刷新率是 60HZ 。 即当页面有变化时,即 1/60 = 16.67 ms

如果刷新率低于 40 , 就明显能感觉到卡顿了。

RAIL 模型

RAIL 模型是以用户角度分析的一个模型。

RAIL 模型分为4个部分:

  • R - Response

事件的响应,期望在 100 ms 内得到反应 。

  • A - Animation

当页面出现变化时,期望可以在 16ms 内得到刷新。否则可能会产生卡顿的现象

  • I - Idle

空闲时间,可以合理利用空闲时间处理一些可能延迟大的任务。减少用户对延迟的感知

  • L - Load

主要的内容的渲染期望在 1s 内完成。否则可能用户可能失去耐心!

ResponseAnimationIdleLoad
100ms 响应16ms刷新空闲时间1000ms 完成主要内容渲染

2. 性能检测 API

2.1 performance

performance API

通过了一些方法,用于记录 mark 时间。 measure 计算时间差 。 getEntries 获取检测记录。

相比 date.now , 它精度大,并且可以检测的时刻很多

它不能被我们用来实例对象。要访问它的实例对象通过 window.performance 可以访问

属性

  • timing

获取 performanceTiming 对象 ,里面记录了需要时间点,比如请求开始,请求介绍,开始解析,渲染完成等事件

已经废除,不过目前还保留,基本上都兼容和支持

  • timeOrigin

time origin 时间源 ,指的是文档开始创建的时间。如果是 worker , 者是 worker 脚本开始运行的时间

方法

  • mark(name)

记录一个时间戳,名称为 name

  • measure(measureName,startMark,endMark)

根据给出的 startMark endMark 的名称,计算两个时间戳的差值,名称为 measuerName , 并缓存

  • now()

返回从 time origin 到当前的时间差值

  • getEntriesByName(name,type)

mark , 和 measuer 都会缓存起来。它们都是一个 performanceEntry entry 包括了这个记录的时间,name 等信息。

通过 name 可以获取对应的 mark 或 measuer . 通过 type 可以指定是 mark, 还是 measuer ,或者其他

  • getEntriesByType()

通过 type 获取 entries

  • geEntries(options)

可用于获取所有的 entries 。也可以通过 options 配置 name 或者 entryType 。可以代替 ByName . ByType 方法

  • clearMarks(name)

删除 name 对应的 mark , 如果没有 name 删除全部

  • clearMeasure(name)

通过 name 删除 measuer , 如果没有 name , 删除全部

2.2 performanceEntry

PerformanceEntry 的实例对象是 performance 时间列表中的一个记录条目对象。

它包括了记录的开始时间,名称,类型等。

除了可以通过 mark , measuer 生成 ,提供 observer 可以生成,浏览器在检测资源加载渲染时也会生成

属性

  • name

enrty 的名称

  • enrtyType

类型

  • navigation : 输入 URL 开始搜索的时间戳类型

  • resource : 资源的类型,比如请求图片 ,css , js

  • mark , measuer : mark ,measuer 生成的类型

  • paint : first-paint , first-contentful-paint 的类型

  • duration

持续时间,一般是资源(resource , mesuer) 有

  • startTime

记录创建时间

2.3 PerformanceTiming

performanceTiming 已经废除了。不过目前浏览器都支持和兼容。

通过 window.performance.timing 获取 performanceTiming 对象。

此对象包括了很多属性,这些属性是记录了一些关键事件发生时的时间戳。比如开始导航,

DSN查询开始, 结束 , TCP 开始,结束 ,资源请求,页面渲染等等。记录的对象是文档!

2.4 PerformanceResourceTiming

该接口可以检索和分析有关加载应用程序资源的详细网络计时数据

它扩展于 performanceEntry 。 通过 performance.getEntriesByType('resource') 可以获取。

获取到的 enrties 是资源的请求,加载,解析等计时时间。

entry 的 name 属性即对应的请求资源路径 ,比如 https://xxx/xx/index.html

它记录了资源从 DNS 查询开始时间 ,DSN结束时间,TCP ,重定向, 请求开始,请求结束等等的时间戳。

developer.mozilla.org/zh-CN/docs/…

2.5 PerformanceNavigationTiming

扩展于 PerformanceResourceTiming 。 记录的是 navigation , 即文档请求加载解析的详细时间数据!(可以是页面或者是 iframe)

通过 performance.getEntriesByType('navigation') 可以获取。

它用于代替 PerformanceTiming 。

它除了具有 PerformanceResourceTiming 的属性

还有 :

  • domComplete
  • domContentLoadEventStart/end
  • unloadEventStart/end

等等的时间戳。

2.6 PerformanceObserver

此API 可以让我们去监听一些 监测性能的事件。

比如监听 mark 相关的事件 ,监听 measuer 相关的事件 。监听 resource 相关的事件 。

如果需要执行一段代码,函数,需要执行的事件可以在执行前后进行 mark 。

但对于资源,如果要及时的获取检测情况,就需要使用 PerformanceObserver 。

var observer = new PerformanceObserver(callback);

callback 是监听的对象被记录时触发。

第一参数是 performance 对象,不同于 window.performance ,是 observer 检测生成的. 第二个承参数是 observer 本身、

属性

  • supportedEntryTypes

可以获取浏览器支持的一些可以检测的类型

"element", "event", "first-input", "largest-contentful-paint", "layout-shift", "longtask", "mark", "measure", "navigation", "paint", "resource"

方法

  • observer(options)

options:

  • type : 可以是 supportedEntryTypes 里的任意一种
  • entryTypes : 不可于 type 一起使用 ,用于需要观察多种类型时使用 ,字符串数组
  • buffered : 加载中检测对象是否应该放入缓存区

即如果加载的时间如果比较久,一些特殊情况下就不考虑了。比如 LCP

  • durationThreshold : 当 duration 大于一定条件时,才算检测有效的条目。

比如监听时间,响应时间超过50ms 才触发回调,就设置为 50

const observer = new PerformanceObserver((list, obj) => {
  list.getEntries()
    .forEach((entry) => {
      // Process "resource" events
    });
});
observer.observe({ type: "resource", buffered: true });

2.7 LargestContentfulPaint

扩展于 performanceEntry .

它记录了 LCP 的检测内容。

浏览器不会自动记录。需要使用 PerformanceObserver 手动检测。

并且对于开始检测前的内容不会做记录。只检测 observer 执行后的内容。

可以触发的是渲染了最大的文字,或图片,或者视频 ,有内容的 canvas 等。

只记录一次,一次记录一种 element 。

它的 enrty 包括元素,加载时间,渲染时间 ,id 等

2.8 PerformanceElementTiming

它类似于 LargestContentfulPaint 。 区别在于。

我们可以指定需要监测的元素 。不过元素需要符合一些条件。和 LargestContentfulPaint 一样。

  • 有文本的标签

  • 图片

  • 有背景图片的标签

  • 有内容的 canvas ,svg

2.9 PerformanceEventTiming

扩展于 performanceEntry

记录了事件从交互到响应的时间。

默认 durationThreshold = 104ms

此时间以内都不会触发回调

可用于测量:FID:从用户首次与应用交互到浏览器实际能够响应该交互的时间点。

developer.mozilla.org/en-US/docs/…

2.10 PerformanceLongTaskTiming

PerformanceLongTaskTiming 接口提供有关占用 UI 线程 50 毫秒或更长时间的任务的信息

type 为 longtask 。

即一个任务,通常是函数。执行的时间超过了 50ms 。那么就可能导致 此任务 占用过多时间。来不及响应其他事件。比如 click, sroll ,那么就可能造成页面的卡顿。

2.11 PerformancePaintTiming

提供 first-paint 和 fcp 的检测信息。

浏览器会自动检测记录。

也可以手动检测 ,type 为 paint

3. 使用 performance API 计算各指标

Load

  • 可以在 window.onload 时,获取一次 performance.now()
  • 可以利用 performanceNavigationEntry
let ob = new PerformanceObserver((es) => {
  es.getEntries().forEach(v => {
    console.log(v.loadEventStart);
  })
  ob.disconnect()
})

ob.observe({
  type: 'navigation'
})

DOMContentLoaded ( DML

  • 监听 DOMContntLoaded 事件
window.addEventListener('DOMContentLoaded', () => {
  console.log("DCL", performance.now());
})
  • 利用 performanceNavigationEntry
let ob = new PerformanceObserver((es) => {
  es.getEntries().forEach(v => {
    console.log(v.domContentLoadedEventStart);
  })
  ob.disconnect()
})

ob.observe({
  type: 'navigation'
})
  • FP ( first paint)

渲染出第一个像素点时的时间点。

  • 第一种方法,手动在 body 后第一个元素添加一个脚本标签。在全局下记录一个时间戳。
  • 第二种,浏览器会自动帮我们检测 ,通过 window.performance 获取。或者手动 observe

浏览器自动检测的和我们手动检测是有区别的。如果是手动的,则需要在 FP 前就 observe 。否则获取到的是 observe 后的 FP ,而不是文档的 FP 。 而浏览器自动检测的,就需要在 FP 发生后才去读取。否则是获取不到的

  window.performance.getEntriesByType('paint').forEach(v => {
    console.log(`${v.name} --- ${v.startTime}`);
  })

获取到的有 ,first-paint 和 first-contentful-paint 。 读取 startTime 即

  • FCP ( First contentful Paint )

contentful 是指文本,图片 ,非空白 Canvas 或 SVG 的时间

而无内容的标签,即使有颜色,大小等,是不会触发 FCP 的。

  window.performance.getEntriesByType('paint').forEach(v => {
    console.log(`${v.name} --- ${v.startTime}`);
  })

FMP ( First Meaningful Paint )

首次有意义的内容的渲染的时间点。这个因为内容的不同,标准也不同。

zhuanlan.zhihu.com/p/81329849

LCP ( largest contentful paint )

指得是渲染中,最大的,有意义内容得渲染。

即渲染面积最大得文本,或者是图片,或者是 canvas 。

一般,如果有文字有图片,当文字渲染的区域更大时,就考虑为文字(与盒子大小无关)。

如果图片更大就是图片,如果图片加载时间太久,则不考虑!

let ob = new PerformanceObserver((es) => {
  console.log("@ob");

  es.getEntries().forEach(v => {
    console.log(v);
  })

  ob.disconnect()
})

ob.observe({
  type: 'largest-contentful-paint'
})

FID (frist input delay)

用于度量用户第一次与页面交互的延迟时间,是用户第一次与页面交互到浏览器真正能够开始处理事件处理程序以响应该交互的时间

通过 observe event 可以测量。不过,一般事件在 100ms 内响应,其实问题不大。默认情况下,durationThreshold 是 104 ms ,因此如果响应事件在 104 以内,是不会触发回调的。

let ob = new PerformanceObserver((es) => {
  es.getEntries().forEach(v => {
    console.log(v.duration);
  })
  ob.disconnect()
})

ob.observe({
  type: 'event',
  durationThreshold: 10
})

4. DevTool 性能检测

利用浏览器的开发者工具,可以对页面进行性能的检测。

Network

通过 network ,可以查看网络发送了什么请求。请求的具体情况等。

比如下图,通过 priority 可以查看请求的优先级。请求是有优先级的。大量并发请求的情况下,除了先后顺序,还有优先级。

另外就是 watefall , 瀑布流 。鼠标悬浮在上面,可以查看请求的各阶段时间点。

点开请求,可以查看具体的请求内容,请求头,响应头, cookie 等

Memory

内存相关。可以查看内存的使用情况。可以用于检测内存泄漏

我不会用

Performance

可以不刷新,进行检测。也可以点击第二个按钮,刷新检测。第三个是清除记录。

控制面板部分

控制面板中有五个选择项和两个下拉框,它们的含义如下:

  • Screenshots:表示是否截取每一帧的屏幕截图,默认会勾选,并且在概览面板中展示随时间变化的截屏动画,如果取消勾选,则不会这哪是这部分内容;

  • Memory:表示是否记录内存消耗,默认不会候选,如果勾选则会在线层面板与统计面板之间展示出各种类型资源的内存消耗曲线;

  • Web Vitals:是谷歌针对网页加载速度和体验所提出的一套指标,这套指标用于测试网页的加载速度及用户体验等,这里不做详细说明;

  • Disable javaScript samples:如果需要模拟手机端的运行环境时则需要勾选,它表示关闭JavaScript样本,减少在手机端运行时的开销;

  • Enable advanced paint instrucmentation(slow):表示是否开启加速渲染工具,用来记录渲染事件的相关细节,该功能比较消耗性能,开启后重新生成检测报告的速度会变慢。

  • Network:在性能检测时,用以切换模拟网络环境,可以模拟弱网(2g/3g)条件下网站的一些表现情况,然后根据弱网的具体表现进行相关优化。;

  • CPU:限制CPU的处理速度,主要用于模拟低俗CPU运行时的性能。

预览面板部分

顶部是 CPU 的使用情况,通过点击第三个版面的 main 可以查看 GPU 的具体使用情况。默认检测完后显示的也是 main

中间是 screenshots 如果有勾选。

底部是 memeory 的堆使用情况。如果有勾选

网络,GPU, Timing 部分

Network 是网络请求。

Frames 是刷新情况

Timing 是一些时间段的记录,比如 FP , FCP , LCP 等

Main 就是 CPU 的使用情况

Raster 是光栅相关的线程

GPU 是渲染引擎使用情况

统计面板

统计面板会根据你点击的内容显示不同的情况。

比如点击请求显示请求的情况,点击 GPU 则显示GPU 耗时等

LightHouse

Lighthouse是一款用于改进网站应用质量的开源自动化检测工具。它会自动的帮我们对网站进行分析。提供解决方法等

4个检测方面

  • Performance : 性能
  • Accessibility : 无障碍 ,主要检测是否方便使用
  • Best Practices : 最佳实践 , 提供一个使用使用的方法,比如推荐使用 https , 增加防 cros
  • SEO : 搜索引擎优化
  • PWA : 渐进式WAB应用

性能检测 6 各指标

分析后给出的建议