前言

上周一面腾讯云智的时候,面试官问我这么个问题:“你知道浏览器的首屏时间怎么查看吗?”我回答进入页面到最后一个请求回收所用的时间,然后他又问:具体有什么指标来表明呢?于是就有了下文

浏览器性能指标

为了描述web页面的性能,开发人员提供了很多可量化的指标来进行分析。比如TTFB、FP、FCP等。指标之间也是有联系的,其中还有部分指标专门为了描述用户交互体验,比如FP、FCP、FSP、FCI、TTI等。下面就来从用户核心指标开始讲述内容。

核心指标

当用户打开一个页面,会经历一个这样的视觉过程:白屏->底图->出现部分内容->首屏内容出现,但图片还在加载中->首屏内容和图片都加载完毕

一般在这个首屏的内容大部分被加载的时候,用户才能开始和页面进行交互等操作,所以如果这段响应的时间很长,就会导致用户的体验很差,下面的几个核心指标描述这些过程的关键变化点,通过它们我们可以来了解用户体验。

  • LCP 最大内容绘制
  • FID 第一次交互的延迟
  • CLS 累计位移偏差

Largest Contentful Paint(LCP)

最大内容绘制,用于记录视窗内最大元素的绘制时间,这个可能随着页面的渲染发生变化。且在用户第一次交互后停止记录。

LCP会持续更新,因此在页面的骨架屏或者loading动画存在的时候,FCP已经记录完了,而LCP因为这个特性,可以让我们知道后续页面的主要内容是什么时候呈现的

最优时间在2.5s内

LCP关注什么元素

  1. <img> 元素
  2. <image>元素内的<svg>元素
  3. <video> 元素
  4. 通过 url() 函数加载背景图片的元素
  5. 包含文本节点或其他内联文本元素子级的块级元素。

改善LCP

改善LCP就要从为什么会造成LCP开始说明

  • 服务器响应时间慢
  • 阻断渲染的JS和CSS
  • 资源加载时间慢
  • 客户端渲染

从以上的角度去改善LCP

服务器优化

服务器涉及到TTFB这个指标,可以从以下几个方面来优化

  • 缓存HTML离线页面,缓存页面资源,减小浏览器对资源的请求(不是首次)
  • 压缩HTML
  • 使用preconnect尽快与服务器建立连接,使用dns-prefetch尽快进行DNS查找
  • 使用CDN

优化阻断渲染的资源

JS和CSS阻断页面的渲染是无可避免的,我们只能通过CSS和JS压缩合并级联内联来减少

优化资源加载时间

上述我们知道LCP只和几个标签有关,那我们就从标签入手优化

  • 对图片进行优化,转WEBP
  • 对重要的资源进行预加载,比如为 style 标签添加 rel="preload" 属性
  • gzip压缩
  • service worker缓存资源

转服务端渲染

SSR

First Input Delay(FID)

首次输入延迟,记录了FCP和TTI之间用户首次与页面交互的时候响应的延迟。

这个指标衡量响应的延迟,也是表明长任务的一个指标。

改善FID

减少JS执行时间

同上LCP的方法

  • 缩小并压缩js
  • 延迟加载首屏不需要的js
  • 尽量减少未使用的polyfill

分解耗时任务

超过50ms的任务都称之为长任务,所以我们可以通过将长任务拆解称为较小的异步任务。

使用Web Worker

主线程阻塞是FID的根本原因,所以使用Web Worker帮助你在和主线程分离的后台线程上运行js,从而改善FID

Cumulative Layout Shift(CLS)

累计位移偏差。也可以理解为视觉稳定性。这个指标是为了记录有些动态插入的内容影响用户的体验诞生的。计算的方法是:位移影响的面积*位移距离

期望值低于0.1是比较好的,说明页面跳来跳去的情况比较少。如果有广告插入对用户的体验也不是很好

改善CLS

位移会造成CLS变大,那么就从这个方面开始改善。

不使用无尺寸的元素

这方面的知识可能很多人都不是很清楚,我们除了要设置图片的长宽之外,还可以指定他的长宽比

1
2
3
img{
aspect-ratio: attr(width)/ attr(height)
}

对于响应式的图片,我们可以这样设置

1
2
3
4
5
6
7
8
9
<img 
width="1000"
height="1000"
src="puppy-1000.jpg"
srcset="puppy-1000.jpg 1000w,
puppy-2000.jpg 2000w,
puppy-3000.jpg 3000w"
alt="ConardLi"
/>

  • 不要在现有的内容之上插入内容,除非是响应式的用户交互。
  • 宁可转换动画,也不要转换触发布局变化的属性的动画

提前给广告位预留空间

很多页面的广告都是动态插入的,所以要为广告位预留空间

字体变化

字体变化可以采用font-display:swappreload的方式提前加载,还有转格式并压缩的方式。

First Paint (FP)

从开始加载到浏览器首次绘制像素到屏幕上的时间,也就是页面在屏幕上首次发生视觉变化的时间。但此变化可能是简单的背景色更新或者不引人注意的内容,她并不代表页面的完整性,可能会报告没有任何可见内容被绘制的时间

测量方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function getFirstPaint() {
let firstPaints = {};
if (typeof performance.getEntriesByType === 'function') {
let performanceEntries = performance.getEntriesByType('paint') || [];
performanceEntries.forEach((entry) => {
if (entry.name === 'first-paint') {
firstPaints.firstPaint = entry.startTime;
} else if (entry.name === 'first-contentful-paint') {
firstPaints.firstContentfulPaint = entry.startTime;
}
});
} else {
if (chrome && chrome.loadTimes) {
let loadTimes = window.chrome.loadTimes();
let {firstPaintTime, startLoadTime} = loadTimes;
firstPaints.firstPaint = (firstPaintTime - startLoadTime) * 1000;
} else if (performance.timing && typeof performance.timing.msFirstPaint === 'number') {
let {msFirstPaint, navigationStart} = performance.timing;
firstPaints.firstPaint = msFirstPaint - navigationStart;
}
}
return firstPaints;
}

First Contentful Paint (FCP)

这个指标用于记录浏览器首次绘制来自DOM内容的时间,内容必须是文本、图片(包含背景图)、非白色的canvas或SVG、也包含正在加载中的Web字体的文本。

该阶段用户看到的可能是一个header或者导航栏,并不一定是用户值得消费的内容

且字体对FCP影响比较大,我们可以使用font-display:swap的方式让浏览器一开始就使用系统的字体,等字体更新好再使用自定义的字体

字体的优化还可以从格式上,比如将:

FCP的测量方式见FP

最优时间
关于这两个指标,有如下的时间体验

我们可以看出在2s以内能完成就算体验优秀,详细的也可以在LightHouse中查看

Time to Interactive(TTI)

首次可交互时间,计算比较复杂,需要满足以下几个条件

  1. FCP指标之后开始计算
  2. 持续五秒没有长任务(执行时间超过50ms)且无两个以上正在进行的GET请求
    3, 往前回溯至5s前的最后一个长任务结束时间。

50ms是谷歌定义的,推荐的响应时间是100ms以内,如果超过了这个时间,用户会有延迟感。

这个指标衡量了响应交互。

Total Blocking Time(TBT)

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

Time to First Byte(TTFB)

服务器有关

浏览器从请求页面开始到接收第一字节的时间,这个时间段内包括 DNS 查找、TCP 连接和 SSL 连接。

DomContentLoaded(DCL)

DomContentLoaded 事件触发的时间。当 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架加载完成。

Load(L)

onLoad 事件触发的时间。页面所有资源都加载完毕后(比如图片,CSS),onLoad 事件才被触发。

关于核心指标

LCP代表了页面的速度,且LCP在目前流行loading和骨架屏的情况下,能体现的东西就更多了。他的指标实时更新,数据更精确,且代表着页面最大元素的渲染时间,通常来说最大元素的快速加载能让用户感觉性能还好。

FID表示页面的交互体验指标,如果他快说明交互的延迟低,会让用户觉得网页流畅。

CLS代表了页面的稳定性,尤其在手机上更为重要。因为收集屏幕小的原因,偏移差越多导致视觉交互越差,降低用户体验。

关于指标收集

Lighthouse

使用到了Lighthouse,这个是Chrome自带的性能指标获取器,会显示出具体的指标名称和时间,以及分数。

web-vitals-extension

可以用这个插件来获取三大核心指标:LCP、FID、CLS

web-vitals 库

使用这个库可以获取CLS、FID、LCP以及FCP、TTFB

使用方法

1
2
3
4
5
6
import {getCLS, getFID, getLCP} from 'web-vitals';

getCLS(console.log);
getFID(console.log);
getLCP(console.log);

Chrome DevTools

打开performance就可以获取指标

代码收集

使用window.performance或其他第三方的库

关于测试

资源加载方面的延迟:使用sleep的方式人为的控制资源的加载时长。

1
<link rel="stylesheet" href="./css/index.css?sleep=3000" />

网络方面的延迟:使用chrome的网速调节,可以方便我们测试占位图,骨架屏的情况。