以用户为中心的前端性能

1. 简介

前端性能跟用户体验息息相关。举个栗子,当你打开乘车码扫码进站,网页白屏了很久才加载出来,延误了乘车时间;当你在微信抢红包时,点击按钮后延迟了一会才开始转圈圈,最终没抢到红包。当出现这样的情况,用户体验就不好了。有研究表明,网页加载时间超过3秒,有一半的用户会失去耐心而离开。由此可见,前端性能对用户体验很重要

那么,什么是前端性能呢?

谈到性能,我们会想到高并发、高吞吐量,但这些是用户无法感知到的。对于用户来说,页面秒开、交互顺畅 ,才会觉得这个网站快。所以,前端性能关注的是页面加载速度和交互响应速度

2. 页面加载

如果页面加载太慢,用户就会失去耐心而离开。那么,浏览器是怎么加载页面的呢?

  • 首先,加载HTML并构建DOM。同时,同步地加载脚本(<script>),异步地加载异步脚本(<script async>) 和图片等资源。
  • 然后,DOM构建完成之后,加载延迟脚本(<script defer> 和 <script type='module'>)。在以上过程中,非异步脚本都会等待CSS加载。
  • 最后,DOM构建完成,所有脚本、CSS和图片等资源加载完成,即页面加载完成。

下图是页面加载的整个生命周期:

关键时间点如下:

  • domInteractive:表示DOM构建完成的时间点(此时JavaScript已经可以访问DOM)。
  • domContentLoadedEventStart:表示domContentLoaded事件处理器开始的时间点。(此时,脚本和CSS已经加载完成,异步脚本除外)
  • domComplete:表示页面加载完成的时间点(包括DOM解析完成,所有脚本、CSS和图片等资源加载完成)。

这些关键时间点,客观地衡量了页面加载速度。但是对用户来说,能直接感知的是白屏时间

对应的指标如下:

  • FCP: First Contentful Paint即首次渲染出内容的时间点。
  • LCP:Largest Contenful Paint即渲染出主要内容的时间点。与FCP相比,用户对LCP的感知会更明显。

3. 交互响应

用户看到页面渲染出来了,就会下意识地去操作页面,这时如果没有及时反馈,用户就会感觉到页面有延迟。

那么,为什么页面没有及时响应呢?

用户输入或点击按钮触发事件,网页会执行事件处理函数。如果处理时间过长,就会阻塞主线程,无法及时处理UI事件,造成页面卡顿。

对应的指标如下:

  • TTI: Time To Interactive,即页面可交互的时间点。
  • FID:First Input Delay,即用户首次输入的延迟时间。
  • long tasks:如果一个任务执行时间超过50ms,就是long tasks。long tasks会阻塞主线程,造成页面卡顿。
  • input delay:从用户输入到页面响应的时间差值。

4. 采集性能数据

网页的加载和渲染是发生在浏览器端的,所以依赖于浏览器提供的API来获取性能数据。

4.1. 采集页面加载性能

javascript 复制代码
new PerformanceObserver((entryList) => {  
  for (const entry of entryList.getEntries()) {  
      console.log(entry)
  }  
}).observe({type: "navigation", buffered: true});

4.2. 采集FCP&LCP

javascript 复制代码
// 获取FCP
new PerformanceObserver((entryList) => {  
  for (const entry of entryList.getEntries()) {  
      console.log(entry)
  }  
}).observe({type: "paint", buffered: true});
javascript 复制代码
// 获取LCP
// 浏览器会多次报告 LCP ,而一般真正的 LCP 是用户交互前最近一次报告的 LCP
new PerformanceObserver((entryList) => {  
  for (const entry of entryList.getEntries()) {  
    console.log('LCP candidate:', entry.startTime, entry);  
  }  
}).observe({type: 'largest-contentful-paint', buffered: true});

4.3. 采集TTI&FID

浏览器没有提供直接获取TTI的API,但有方法可以计算出TTI。计算方法是:找到FCP之后的第一个安静窗口,窗口前的最后一个long task结束时间就是TTI。

安静窗口需满足三个条件:1.没有long task;2.窗口内get请求不超过2个;3.窗口时间不少于5s。

javascript 复制代码
// 获取FID
new PerformanceObserver(function(list, obs) {  
  const firstInput = list.getEntries()[0];  
  
  // Measure the delay to begin processing the first input event.  
  const firstInputDelay = firstInput.processingStart - firstInput.startTime;  
  // Measure the duration of processing the first input event.  
  // Only use when the important event handling work is done synchronously in the handlers.  
  const firstInputDuration = firstInput.duration;  
  // Obtain some information about the target of this event, such as the id.  
  const targetId = firstInput.target ? firstInput.target.id : 'unknown-target';  
  // Process the first input delay and perhaps its duration...  
  
  // Disconnect this observer since callback is only triggered once.  
  obs.disconnect();  
}).observe({type: 'first-input', buffered: true});

4.4. 采集long task

javascript 复制代码
// 获取long task
new PerformanceObserver((entryList) => {  
  for (const entry of entryList.getEntries()) {  
    console.log(`startTime=${entry.startTime},duration=${entry.duration}`);  
  }  
}).observe({type: 'longtask', buffered: true});

4.5. 性能测试工具

以下是一些常用的性能测试工具:

  1. lighthouse

Lighthouse 是 Google 开发的一款性能测试工具。支持Chrome Extension手动使用,还可以通过 Node CLI 集成到流水线自动化测试。

  1. www.webpagetest.org

如果要测试国外网站,可以用webpagetest。

5. 性能基线

根据用户对网页性能的感知,有了FCP、LCP、TTI、FID等性能指标来衡量网页性能。那么,如何划分优劣呢?为此,Google提供了一个标准的性能基线。我们可以参考这个基线来监控网页性能的达标率。需要注意的是,随着软硬件的升级,基线本身是会有调整的。另外,设备性能和网络环境对网页性能也有很大影响,例如IOS上报的性能指标一般要优于安卓。

指标
FCP [0,1800ms] [1800ms,3000ms] >3000ms
LCP [0,2500ms] [2500ms,4000ms] >4000ms
TTI [0,3800ms] [3800ms,7300ms] >7300ms
FID [0,100ms] [100ms,300ms] >300ms

6. 总结

前端性能对用户体验很重要。如果页面加载太慢,用户就会失去耐心而离开。页面加载出来后,用户会下意识地去操作页面,如果页面没有及时给出反馈,用户就会感知到页面延迟。因此,针对用户对性能地感知,可通过FCP、LCP、FID、TTI、long task、input delay等性能指标,衡量页面性能。通过采集性能数据,有效地帮助分析网页性能,提升性能,提升用户体验。

参考资料

海愚-如何重新认知性能优化及其度量方法

MDN Web Performance

Web Performance Working Group

前端监控系列3 | 如何衡量一个站点的性能好坏

深入浅出 Performance 工具 & API

相关推荐
Mr_Mao1 小时前
Naive Ultra:中后台 Naive UI 增强组件库
前端
前端小趴菜053 小时前
React-React.memo-props比较机制
前端·javascript·react.js
摸鱼仙人~4 小时前
styled-components:现代React样式解决方案
前端·react.js·前端框架
sasaraku.4 小时前
serviceWorker缓存资源
前端
RadiumAg5 小时前
记一道有趣的面试题
前端·javascript
yangzhi_emo5 小时前
ES6笔记2
开发语言·前端·javascript
yanlele6 小时前
我用爬虫抓取了 25 年 5 月掘金热门面试文章
前端·javascript·面试
中微子7 小时前
React状态管理最佳实践
前端
烛阴7 小时前
void 0 的奥秘:解锁 JavaScript 中 undefined 的正确打开方式
前端·javascript
中微子7 小时前
JavaScript 事件与 React 合成事件完全指南:从入门到精通
前端