Loading

前端页面性能指标

基本指标介绍

首次绘制(First Paint,FP)

FP 是时间线上的第一个“时间点”,是指浏览器从响应用户输入网址地址,到浏览器开始显示内容的时间,简而言之就是浏览器第一次发生变化的时间。

首次内容绘制(First Contentful Paint,FCP)

FCP(全称“First Contentful Paint”,翻译为“首次内容绘制”),是指浏览器从响应用户输入网络地址,在页面首次绘制文本,图片(包括背景图)、非白色的 canvas 或者 SVG 才算做 FCP,有些文章说 FCP 是首屏渲染事件,这其实是不对的。

可交互时间(Time to Interactive,TTI)

TTI,翻译为“可交互时间”表示网页第一次完全达到可交互状态的时间点。可交互状态指的是页面上的 UI 组件是可以交互的(可以响应按钮的点击或在文本框输入文字等),不仅如此,此时主线程已经达到“流畅”的程度,主线程的任务均不超过 50 毫秒。在一般的管理系统中,TTI 是一个很重要的指标。

最大内容绘制(Largest Contentful Paint,LCP)

LCP(全称“Largest Contentful Paint”)表示可视区“内容”最大的可见元素开始出现在屏幕上的时间点。

首次有效绘制(First Meaning Paint, FMP) 废弃

FMP(全称“First Meaningful Paint”,翻译为“首次有效绘制”表示页面的“主要内容”开始出现在屏幕上的时间点,它以前是我们测量用户加载体验的主要指标。本质上是通过一个算法来猜测某个时间点可能是 FMP,但是最好的情况也只有 77%的准确率,在 lighthouse6.0 的时候废弃掉了这个指标,取而代之的是 LCP 这个指标。

performance

performance 介绍

performance 对象是专门用来用于性能监控的对象,内置了一些前端需要的性能参数。

performance.now()方法

performance.now() 返回 performance.navigationStart 至当前的毫秒数。performance.navigationStart 是下文将介绍到的可以说是浏览器访问最初的时间测量点。

performance.now(); // 24614164.599999994

performance.timing

performance.timing

performance.getEntries()方法

浏览器获取网页时,会对网页中每一个对象(脚本文件、样式表、图片文件等等)发出一个 HTTP/HTTPS 请求。performance.getEntries() 方法以数组形式,返回一个 PerformanceEntry 列表,这些请求的时间统计信息,有多少个请求,返回数组就会有多少个成员。

performance.getEntriesByType('paint')

指标计算方法

首屏和白屏

白屏时间是指浏览器从响应用户输入网址地址,到浏览器开始显示内容的时间,一种比较简单的做法是在 body 标签之前获取当前时间 - performance.timing.navigationStart,或者直接获取 performance 中关于 paint 的两个数据,都可以直接作为白屏数据,这两个数据一般差别不大。

首次绘制 FP 包括了任何用户自定义的背景绘制,它是首先将像素绘制到屏幕的时刻。

首次内容绘制 FCP 是浏览器将第一个 DOM 渲染到屏幕的时间。该指标报告了浏览器首次呈现任何文本、图像、画布或者 SVG 的时间。

也可以使用其他的计算方法:白屏时间 = 页面开始展示的时间点 - 开始请求的时间点。

TTI

关于 TTI 可以首先了解下谷歌提出的性能模型 RAIL:

RAIL
  1. 响应:输入延迟时间(从点按到绘制)小于 100 毫秒。用户点按按钮(例如打开导航)。
  1. 动画:每个帧的工作(从 JS 到绘制)完成时间小于 16 毫秒。用户滚动页面,拖动手指(例如,打开菜单)或看到动画。拖动时,应用的响应与手指位置有关(例如,拉动刷新、滑动轮播)。此指标仅适用于拖动的持续阶段,不适用于开始阶段。
  1. 空闲:主线程 JS 工作分成不大于 50 毫秒的块。用户没有与页面交互,但主线程应足够用于处理下一个用户输入。
  1. 加载:页面可以在 1000 毫秒内就绪。用户加载页面并看到关键路径内容。

我们可以通过 domContentLoadedEventEnd 来粗略的进行估算:

TTI:domContentLoadedEventEnd - navigationStart

谷歌实验室也提供了更加便捷准确的 api 包进行测算 tti-polyfil:

import ttiPolyfill from "./path/to/tti-polyfill.js";
ttiPolyfill.getFirstConsistentlyInteractive(opts).then((tti) => {
  // Use `tti` value in some way.
});

LCP

在过去,我们也有推荐的性能指标,如:FMP (First Meaningful Paint)SI (Speed Index)可以帮我们捕获更多的首次渲染之后的加载性能,但这些过于复杂,而且很难解释,也经常出错,没办法确定主要内容什么时候加载完。

根据 W3C Web 性能工作组的讨论和 Google 的研究,发现度量页面主要内容的可见时间有一种更精准且简单的方法是查看 “绘制面积” 最大的元素何时开始渲染。

所谓绘制面积可以理解为每个元素在屏幕上的 “占地面积” ,如果元素延伸到屏幕外,或者元素被裁切了一部分,被裁切的部分不算入在内,只有真正显示在屏幕里的才算数。图片元素的面积计算方式稍微有点不同,因为可以通过 CSS 将图片扩大或缩小显示,也就是说,图片有两个面积:“渲染面积”与“真实面积”。在 LCP 的计算中,图片的绘制面积将获取较小的数值。例如:当“渲染面积”小于“真实面积”时,“绘制面积”为“渲染面积”,反之亦然。

页面在加载过程中,是线性的,元素是一个一个渲染到屏幕上的,而不是一瞬间全渲染到屏幕上,所以“渲染面积”最大的元素随时在发生变化。如果使用 PerformanceObserver 去捕获 LCP,会发现每当出现“渲染面积”更大的元素,就会捕获出一条新的性能条目。

如果元素被删除,LCP 算法将不再考虑该元素,如果被删除的元素刚好是 “绘制面积” 最大的元素,则使用新的 “绘制面积” 最大的元素创建一个新的性能条目。

该过程将持续到用户第一次滚动页面或第一次用户输入(鼠标点击,键盘按键等),也就是说,一旦用户与页面开始产生交互,则停止报告新的性能条目。

可以直接使用 PerformanceObserver 来捕获 LCP:

const observer = new PerformanceObserver((entryList) => {
  const entries = entryList.getEntries();
  const lastEntry = entries[entries.length - 1];
  const lcp = lastEntry.renderTime || lastEntry.loadTime;
  console.log("LCP:", lcp);
});
observer.observe({ entryTypes: ["largest-contentful-paint"] });

LCP 也不是完美的,也很容易出错,它会在用户进行交互后就停止捕获,可能会获取到错误的结果,如果有占据页面很大的轮播图也会产生问题会不断的更新 LCP

LCP 也有现成的计算工具库 web-vitals:

import { getLCP } from "web-vitals";

// Measure and log the current LCP value,
// any time it's ready to be reported.
getLCP(console.log);
posted @ 2021-09-08 17:21  Frank-Link  阅读(1669)  评论(0编辑  收藏  举报