乐趣区

关于前端:我的前端性能优化体系总结

前言

当咱们要掂量剖析一个网页的性能时,没有一个确切指标值能间接反映网页整体性能如何。于是,在网页加载的过程中,咱们须要抓住各个要害工夫点来进行综合剖析,这些就是须要理解的性能指标了。

理解了性能指标,接下来就须要借助工具或平台来测量以及上报了;上报后,咱们要针对对应问题来使用性能优化办法进行优化。

对于前端性能优化办法,有很多相似的雷同的性能优化文章都有介绍了,本文还是会提及并改变,对一些办法谈谈我本人的认识以及公司我的项目实际的状况。

本文并不对前端性能体系各个中央做十分详尽的解释,只是抛出次要的重点进行抛砖引玉,同时介绍一些性能优化办法的细节点。

性能指标

性能指标的分类形式各样,如从用户体验的角度可分为文档加载相干的(TTFB、DCL、L),内容出现相干的(FP、FCP、FMP),交互响应相干的(FID、FSP)

在这就粗略分为两大类解决了,三大外围指标与其它常见的性能指标

三大外围指标

以后网站外围 Web 指标指标形成侧重于用户体验的三个方面——_加载性能_、交互性 视觉稳定性——并包含以下指标(及各指标相应的阈值):

  • Largest Contentful Paint (LCP):最大内容绘制,测量 加载 性能。为了提供良好的用户体验,LCP 应在页面首次开始加载后的 2.5 秒 内产生。
  • First Input Delay (FID):首次输出提早,测量 交互性 。为了提供良好的用户体验,页面的 FID 应为100 毫秒 或更短。
  • Cumulative Layout Shift (CLS):累积布局偏移,测量 视觉稳定性。为了提供良好的用户体验,页面的 CLS 应放弃在  0.1.   或更少。

LCP

Largest Contentful Paint 最大内容绘制 (LCP) 代表代表着页面最大元素的渲染工夫,通常来说页面中最大元素能疾速渲染会让用户感觉页面性能还不错。该工夫会随着页面渲染变动而变动,因为页面中的最大元素在渲染过程中可能会产生扭转,另外该指标会在用户第一次交互后进行记录。

最大内容绘制考量的元素类型为:

  • <img>元素
  • 内嵌在 <svg> 元素内的 <image> 元素
  • <video>元素(应用封面图像)
  • 通过 url() 函数(而非应用 CSS 突变)加载的带有背景图像的元素
  • 蕴含文本节点或其余行内级文本元素子元素的块级元素

如下是最大内容绘制的工夫点

FID

First Input Delay 首次输出提早 记录用户和页面首次交互操作所破费的工夫,即是说用户与页面交互时(如点击链接或按钮),页面能够在多长时间内作出反馈。

FID 指标会影响用户对页面交互性和响应性的第一印象。为了提供良好的用户体验,页面的 FID 该当小于 100 毫秒。

还有一个性能指标 TTI(Time to Interactive)它反映的是用户什么时候能够开始和页面进行交互,但如果用户在 TTI 的工夫内,没有与页面产生交互,TTI 是影响不到用户的;而如果想要晓得 TTI 对用户的影响,须要 FID 这个指标,不同用户与网页发送交互的工夫是不同的,所以对应的 FID 也不同

CLS

Cumulative Layout Shift 累积布局偏移 (CLS) 测量整个页面生命周期内产生的所有意外布局偏移中最大一连串的布局偏移分数,CLS 分数越低,代表页面的布局越稳固。在手机上这个指标更为重要。因为手机屏幕较小,CLS 值大的话会让用户感觉页面体验做的很差。

比方在页面未加载齐全时,想要点击页面某个未知,后果页面的广告刚刚加载完动静注入了页面,导致点击的中央被偏移,点到了广告,造成用户交互行为不冀望的后果。

CLS 较差的最常见起因为:

  • 无尺寸的图像
  • 无尺寸的广告、嵌入和 iframe
  • 动静注入的内容
  • 导致不可见文本闪动 / 无款式文本闪动的网络字体
  • 在更新 DOM 之前期待网络响应的操作

对于如何优化 CLS,能够参考该文章:优化 Cumulative Layout Shift 累积布局偏移

其它性能指标

  • FP(First Paint)首次绘制

FP 指的是页面首次绘制像素的工夫(不包含默认背景绘制),即为页面在屏幕上首次产生视觉变动的工夫。在 Chrome 的 Performance 面板可看到该指标:

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

FCP 指浏览器在页面渲染第一帧内容 DOM(包含任何文本、图片、SVG、非空白 canvas 等)的工夫点。

由上述可知,FP 产生的工夫肯定小于等于 FCP。

如下是官网 Lighthouse 的 FCP 评分的工夫区间,如果 FP 和 FCP 能在 1.8 秒内实现就算体验优良

  • FMP(First Meaningful Paint)首次有意义绘制

首次无效绘制,标记配角元素渲染实现的工夫点,配角元素能够是视频网站的视频控件,内容网站的页面框架也能够是资源网站的头图等。

目前对 FMP 尚无标准化的定义,因为比拟难以用通用的形式确定 无效 / 有意义 的渲染。对于博客网站来说,渲染出题目与首屏文字就是首要内容,对于商城 / 图片网站来说,渲染图片是首要内容,才是有意义的渲染工夫。

比方掘金文章详情页,如果头图的重要性大于题目的话,那它就是无效绘制

以前应用 Lighthouse 工具是有该指标评分的,因为难以标准化,现 Lighthouse 6.0 已弃用,应用了 LCP 指标来代替,具体可见

  • DCL(DOMContentLoaded)DOM 解析实现

当  DOMContentLoaded  事件触发时,仅当  DOM  解析实现,不包含样式表,图片等

在文档中没有脚本时,HTML 被齐全加载以及解析时,DOMContentLoaded 事件会被触发,无需期待样式表、图片等;如果文档中蕴含脚本,则脚本会阻塞 HTML 文档的解析。

  • L(Onload Event)onload 事件触发

当  onload  事件触发时,代表页面上所有的 DOM、样式表、脚本、图片都已加载实现,即整个页面齐全加载实现

对于 DOMContentLoaded 与 Load 的区别可看掘金网站的 performance 指标对应的快照图比照:

DOMContentLoaded:

Load:

为了更形象看出 DOMContentLoaded 与 Load 的区别,能够看这个容易看出区别的[例子]
(https://testdrive-archive.azu…)

  • SI(Speed Index)速度指数

用来掂量页面可见内容填充快慢的指标。该指标涵盖了浏览器何时出现所有元素,包含不可见的脚本和影响性能的元素;

在用户的角度,它掂量的是用户残缺查看页面内容所需的工夫,该指标越低越好。

该指标在 Lighthouse 工具可测量。

  • TTI(Time To Interactive)首次可交互工夫

可交互状态指的是页面上的 UI 组件是能够交互的(比方能够响应按钮的点击等)。通过 TTI 能够让咱们理解咱们的页面须要多久能够真正达到“可用”的状态,可能疾速牢靠响应用户操作所需的工夫长短。

首次可交互工夫,TTI(Time to Interactive)。这个指标计算过程稍微简单,它须要满足以下几个条件:

  1. 先进行 First Contentful Paint 首次内容绘制 (FCP)后开始计算。
  2. 搜寻时长至多为 5 秒的宁静窗口。宁静窗口的定义为:没有长工作(长工作为执行工夫超过 50 ms 的任何工作)且不超过两个正在解决的网络 GET 申请。
  3. 往前回溯至宁静窗口之前的最初一个长工作完结工夫。(如果没有找到长工作,则与 FCP 值雷同)
  • TTFB(Time To First Byte)接管首字节工夫

浏览器从申请页面开始到接管第一字节的工夫,这个时间段包含 DNS 查找、TCP 连贯和 SSL 连贯。

TTFB 是由三个次要过程组成的:

  1. 浏览器发送 HTTP 申请所破费的工夫
  2. 服务器解决该申请所破费的工夫
  3. 服务器将响应的第一个字节发送回浏览器所破费的工夫

它掂量的是服务器的响应速度,越快意味着用户期待网站开始加载的工夫越少

  • TBT(Total Blocking Time)阻塞总工夫

TBT 测量页面被阻止响应用户输出(例如鼠标点击、屏幕点击或按下键盘)的总工夫。总和是 FCP 和 TTI 之间所有长工作的 阻塞局部 之和。任何执行工夫超过 50 毫秒的工作都是长工作。50 毫秒后的工夫量是阻塞局部。例如,如果 Lighthouse 检测到一个 70 毫秒长的工作,则阻塞局部将为 20 毫秒。

  • FSP(First Screen Paint)首屏工夫

该指标灵活性较大,示意页面从开始加载到首屏内容全副绘制实现的工夫,即用户能够看到首屏的全部内容

性能测量工具

在理解完性能指标之后,就须要借助一些性能测量工具来获取这些指标的值了

Chrome DevTools

Chrome 开发工具是日常开发过程接触最多的,个别针对性优化时,咱们会关注 Network 和 Performance 面板,对于 Performance 面板的简要阐明可见我该篇文章:浅析 Chrome Devtools 的 Performance 面板

Lighthouse

Lighthouse 用来生成网页的性能评测报告,该工具是性能评分工具中应用频率较高的,装置 Lighthouse 插件,生成报告查看各指标评分。

倡议在无痕浏览器下进行测试,排除其它烦扰因素测量进去较为精确,后果如下图:

不仅如此,还能在报告中看到一些可能有用的优化倡议:

WebPageTest

WebPageTest 用来进行整体的网站品质评估、一站式性能评估。

如下图为官网:

应用步骤

  1. 输出要测试的网页网址
  2. 抉择高级配置
  3. 抉择地理位置,从靠近你地位最近的测试机器进行测试,并抉择 Chrome 浏览器
  4. 点击 Start Test

后果剖析

首次视图(First View):首次视图的测试,将会把浏览器的缓存和 Cookie 革除,示意访问者第一次拜访该网页的状况

申请瀑布图

点击 Waterfall 显示的瀑布图,能够看到具体的参数详情

web-vitals

上述是通过工具来测量的,假如咱们想在 JS 代码中来获取,最简略的形式就是应用集成 Web Vitals 的 JS 库,该我的项目是由 Chrome 发动的,可获取 CLS、FID、FCP、LCP、TTFB 指标。

应用办法如下:

import {getCLS, getFID, getLCP} from 'web-vitals'

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

此话,还有对应的 Chrome 扩大工具:web-vitals-extension

性能监控

当初公司谈性能监控,次要就是指用户与实在的网页交互中采集和上报记录性能数据,进行评估。因为我也没做过由 0 到 1 的性能监控平台,这方面也没有太多实战经验,就简略的分享上面一些点。

寻找性能瓶颈

做性能优化前,个别要不是曾经发现了性能瓶颈,要么就是通过指标上报发现什么性能问题,才能够围绕对应性能指标,采取优化伎俩进行优化。

性能指标采集与上报

web-vitals
当收集浏览器端每个用户外围性能指标时,可通过  web-vitals  收集并通过  sendBeacon  上报到打点零碎。

window.performance.timing

很多性能采集库,都基于该对象进行获取计算各种指标,该对象有很多性能相干的工夫戳记录:

具体字段解释可见:PerformanceTiming 字段

值得注意的是,在将来该 Performance.timing API 会被废除,应用 PerformanceNavigationTiming 代替

有趣味理解前端性能监控的能够看下下列这些文章:

  • 利用性能前端监控,字节跳动这些年教训都在这了
  • 前端监控体系搭建
  • 前端监控平台系列:JS SDK(已开源)

优化伎俩

网络

动态资源应用 CDN

当网站所挂服务器离用户越来越远时,拜访网站提早越高。CDN(内容散发网络)就是为了解决这一问题,在多个不同地理位置部署 Web 服务器,依据用户地位调配最近的资源,缩短申请工夫达到优化加载速度,升高传输提早的成果。CDN 域名个别都会缓存到本地中,申请速度也较快。

如果公司没有搭建本人的 CDN,在优化我的项目想要一些图片 /CSS 库 /JS 库通过 CDN 引入,收费的 CDN 链接请切记思考危险,如果 CDN 链接挂了(如果有官网 CDN 链接,通常挂的概率也比拟低),你是否有兜底计划,没有请别随便援用收费 CDN。

缩小不必要的 HTTP 申请

一个残缺的 HTTP 申请须要经验连贯与开释过程,须要肯定的工夫,缩小 HTTP 申请能节俭肯定工夫。

单纯说缩小 HTTP 申请这个做法在理论工作中是须要衡量的,不是想缩小就缩小。

在我的项目中更应该重视的是:缩小不必要的 HTTP 申请。比方接口申请后缓存了,发现在一些场景切换中,又反复申请了;或者在一些基本没用到该接口的其它页面,也申请了接口,这时就须要进行缩小申请优化。

应用 HTTP2(更快的传输)

HTTP1.1 版本存在的问题:线程阻塞,在同一时间,同一域名的申请有肯定的数量限度,超过限度数目的申请会被阻塞。

HTTP2 个性:

  • 反对二进制传送:解析速度更快
  • 反对多路复用:多个申请能够共用一个 TCP 连贯,进步了连贯的利用率,升高提早
  • 压缩算法压缩头部:减小了传输的体积。且将雷同的首部存储起来,仅发送不同的局部,也能够节俭流量和放慢申请工夫

因为 HTTP2 反对多路复用,可并行申请的个性,雪碧图 这个性能优化点也随之过期,当初角度看,雪碧图保护老本也高,根本不会应用了。

HTTP 缓存

为了不让用户每次拜访网站都须要从新申请文件,能够通过设置 HTTP 缓存(强缓存 / 协商缓存)来进行管制,合乎缓存条件时间接读取缓存,缩小发送申请速度,能进步加载速度。

落到实地,大部分进到公司外面这些都是早配好的。或者这是后端解决的前端没插手机会,如果前端接入 Node 的同学倒能够去搞搞,这一部分就不细说了,有趣味入手试的能够看我这篇文章:入手搞懂 HTTP 缓存机制

启用 Gzip 压缩

Gzip  通过 LZ77 算法与 Huffman 编码来压缩文件,反复度越高的文件可压缩的空间就越大,对 JS、CSS、HTML 等文本资源均无效。当 Nginx 返回 js 文件的时候,会判断是否开启 gzip,而后压缩后再返回给浏览器。

该压缩办法须要 Nginx 配置 也开启 Gzip 压缩,单纯前端通过 webpack 插件开启 Gzip 压缩是不能达到优化成果的

图片

图片懒加载

先不给图片设置 src 门路,当图片呈现在浏览器可视区域时,才去加载图片,这就是提早 / 懒加载。

图片设置 data-src属性在页面不可见时图片不会加载。

图片懒加载思路:

  • 先在 img 标签设置自定义属性 data-src
  • 首屏展现可视区域内的图片(计算对应页面可见时)src 值替换为 data-src,加载图片

在理论场景中社区已有对应的各种 lazyLoad 库可应用

图片压缩

利用一些在线工具或插件,能够对图片进行压缩,适当的压缩大小通常看不出来区别。

webpack 的话有 image-webpack-loader,在线网站比方有 TinyPNG

缩略图

点击再或加载到之后再查看清晰 / 大图

如果有一个 1920 * 1080 大小的图片,用缩略图的形式展现给用户,并且当用户鼠标悬停在下面时才展现全图。如果用户从未真正将鼠标悬停在缩略图上,则节约了下载图片的工夫。

所以,能够用两张图片来进行优化。一开始,只加载缩略图,当用户悬停在图片上时,才加载大图

应用 Web Workers

JavaScript 语言是单线程,所有与浏览器 UI 无关的长时间运行脚本工作只能在一个线程上实现,一次只能做一件事。如果是简单的计算,则页面运行可能会被阻塞。

此时能够用 Web Worker 进行解决与浏览器 UI 无关的长时间运行脚本。Web Worker 为 Web 内容在后盾线程中运行脚本提供了一种简略的办法。线程能够执行工作而不烦扰用户界面。

Web Workers API

服务端渲染 SSR

  • 客户端渲染:客户端获取 HTML,下载 JS 文件运行生成 DOM,渲染页面
  • 服务端渲染:服务端间接返回 HTML 文件,客户端只需解析 HTML

以后应用 Vue/React 开发的网站,只有不是对 SEO 有要求,大部分都是采纳的客户端渲染。而如果网站要谋求 SEO 好和首屏速度快的话,那就可采纳服务端渲染。因为它只需加载一个渲染结束的 HTML 文件,比客户端渲染要更快。

不过这种优化近乎重构网站了,通常要求 SEO 的这种一开始我的项目最好就定好技术栈,中途接入的话,要么重构,要么能够应用改变较小的预渲染。

缩小打包体积

压缩资源体积

该种形式是我工作中实际最多的了,打包体积减小能够缩小文件下载工夫,让用户体验更好。通常会借助 webpack 插件webpack-bundle-analyzer 来进行剖析。

在 webpack 能够应用如下插件进行压缩:

  • HTML:html-webpack-plugin
  • CSS:css-minimizer-webpack-plugin
  • JavaScript:terser-webpack-plugin

动静导入

当页面中有一个文件过大并且还不肯定用到的时候,并不需要全副的 JS 模块,这时就能够到触发时才进行导入。这样能够缩小首页包体积,放慢首页的申请速度。

借助 Webpack 配合 ES6 的按需加载 import 办法,对代码进行打包宰割,动静导入之后,触发时会加载新的chunk.js

// before
import {toast} from './toastify'
toast('Hello World')

// after
import('./toastify').then((module) => {module.toast('Hello World')
})

具体能够看下我这篇文章的例子:我的项目优化实际:Webpack 动静导入 react-toastify

Tree Shaking

Webpack 打包自身反对 tree shaking,如果进一步优化,可能就得从库自身找起。比方 lodash 不反对 Tree Shaking,能够应用 lodash-es 来代替

应用更小的库代替

比方应用体积更小的 dayjs 来代替moment

应用事件委托

增加到页面上的事件数量会影响页面的运行性能,如果增加的事件过多,会导致网页的性能降落。采纳事件委托的形式,能够大大减少注册事件的个数。

应用事件委托的益处:

  • 进步性能
  • 节俭内存占用,缩小事件注册
  • 实现当新增子对象时无需再次对其绑定

CSS

升高 CSS 选择器的复杂性

对于 CSS 选择器没有刻意优化的必要,因为最慢和慢快的选择器性能差异十分小,平时应用只需记住上面几点

  1. 放弃简略,不要应用嵌套过多过于简单的选择器
  2. 通配符和属性选择器效率最低,须要匹配的元素最多,尽量避免应用
  3. 不要应用类选择器和 ID 选择器润饰元素标签,如h3#markdown-content,这样多此一举,还会升高效率(CSS 选择器是从右向左匹配的)

理解具体可看该文 CSS 渲染原理以及优化策略

应用 transform 和 opacity 属性更改来实现动画

在 CSS 中,transforms 和 opacity 这两个属性更改不会触发重排与重绘,它们是能够由合成器(composite)独自解决的属性。

渲染优化

缩小重绘重排

  • 用 JavaScript 批改款式时,最好不要间接写款式,而是替换 class 来扭转款式
  • 须要对元素进行简单操作时,能够先暗藏元素(display:none)操作实现后再显示
  • 须要创立多个 DOM 节点时,应用 DocumentFragment 创立完最初再一次性退出文档

优化高频事件

当页面有一些事件频繁触发时,为了优化体验,须要对这类事件进行调用次数的限度,于是能够应用防抖与节流来缩小调用频率。

  • 防抖:一段时间后只执行一次,将屡次执行变为最初一次执行
  • 节流:在固定的频率执行,将屡次执行变为在规定工夫内只执行一次

优化动画

  • 优先应用 CSS 来实现动画成果
  • 应用 translateZ/translate3d 开启硬件加速
  • 正当应用 requestAnimationFrame 代替 setTimeout

虚构列表优化

如果在视口内列表有较多数据显示(如多达几百上千),如果数据量过大产生过多的 DOM 会造成页面卡顿,此时能够应用虚构列表,监听视口地位变动,从而对视口内的虚构列表进行管制。

  1. react-virtualized
  2. react-window

预加载(加载程序)

preload/prefetch  可管制 HTTP 优先级,从而达到要害申请更快响应的目标。

<link rel="prefetch" href="style.css" as="style" /> <link rel="preload" href="main.js" as="script" />
  1. preload 优先级较高,提前加载较晚呈现,但对以后页面十分重要的资源
  2. prefetch 优先级较低,提前加载后继路由须要的资源。个别用以加载其它路由资源,如当页面呈现 Link,可 prefetch 以后 Link 的路由资源

放弃库版本最新(正当评估)

我的项目中用到的一些要害库或打包体积较大的开源库,要放弃关注,因为这些开源库也会随着版本做优化迭代,因为放弃版本最新有必要性。然而,每次大版本升级前,要做好正当评估,如果有重大 bug 或 breaking change,则审慎起来不要随便降级。

比方从 Webpack4 降级到 Webpack5 版本,就曾经做了较多优化了,具体可见降级 Webpack5 实际

去除生产环境日志

开发时在控制台打印了很多信息,这些信息在开发时能够帮忙调试和定位。

但如果在控制台打印大量数据会影响页面的整体性能,因而在生产环境倡议敞开日志,且能够避免普通用户看到一些敏感日志。

对于该项解决,能够自定义日志打印类,在生产环境默认敞开,但可通过浏览器参数关上;也能够应用 Webpack 插件在线上来进行敞开 console.log 打印。

结语

本文对前端性能体系进行简略的点进行介绍,其中优化伎俩只介绍了常见的,开发环境的性能优化没有列出以及性能监控局部没有补全. 其中单从 Webpack 作为工具的角度,就有很多性能优化点能够列出,这个网上曾经有很多文章介绍就不一一列出了。

心愿后续能写出一些更好的梳理文章笔记,本文仅供参考。

参考文章

  • Web Vitals
  • 工作中如何进行前端性能优化(23 种优化 +10 种定位形式
  • 前端性能优化 24 条倡议(2020)
  • 写在 2021 的前端性能优化指南
退出移动版