vue项目你一定会用到的性能优化!
时间:2023-06-13 11:37:00
提起性能优化
很多人面前的面试经历是否历历在目?反正在我看来,性能优化永远是前端领域。热度之王
。
而且本渣最近的维修项目恰好在这个方向上下了很大的功夫,一些经验都奉上了,希望对大家有所帮助!
性能优化标准
由于性能优化,他必须有一个公认的标准,这是我们多次听到的Lighthouse
很多单位都有自己的性能监控平台,我们只需要介绍相应的sdk,然后你可以在平台上分析你页面上存在的性能问题。你学的很神奇吗?
事实上,除了苛刻的业务外,还需要特殊的定制
,在大多数情况下,我们单位的性能优化平台实际上是使用无头浏览器(Puppeteer)跑Lighthouse
。
在了解了我们单位性能监控平台的原理后,我们可以进行有针对性的性能优化,即面向Lighthouse
编程
Lighthouse
lighthouse 是 Google Chrome 开源自动化工具可以收集多个现代网页的性能指标并进行分析 Web 应用性能和生成报告为开发人员性能优化提供了参考方向。
说起Lighthouse
现代谷歌浏览器中产业已经集成
他可以分析出我们的页面性能,通过几个指标
Lighthouse 测量以下性能指标:
-
第一次绘制内容(First Contentful Paint)。即浏览器首次将任何内容(如文字、图像、canvas 等)在屏幕上上的时间点。
-
可交互时间(Time to Interactive)。指所有页面内容均已成功加载,并能快速响应用户操作的时间点。
-
速度指标(Speed Index)。衡量屏幕上第一个屏幕上可见内容的速度。在第一次加载页面的过程中,尽可能多地显示内容,这通常会给用户带来更好的体验,所以速度指标的值越小越好。
-
总阻塞时间(Total Blocking Time)。指First Contentful Paint 第一次绘制内容 (FCP)与Time to Interactive 可交互时间 (TTI)之间的总时间
-
绘制最大内容(Largest Contentful Paint)。最大标准报告视口中最大图像或文本块的呈现时间
-
累积布局偏移(# Cumulative Layout Shift)。衡量页面整个生命周期中每个元素的非预期布局偏移得分的总和。当两个渲染帧中每个视觉元素的起始位置不同时,会发生LS(Layout Shift)。
一般来说,根据我的经验,由于性能监控平台和本地平台差异
,本地可能需要实现70分,只有在网上才能达到通过状态,如果有性能优化的需要,大家都可以酌情处理(但我觉得,通过就可以了, 毕竟大学考试有句话:60分万岁,61分浪费
,传承不能丢,我们要把更多的时间,放在更重要的事情上!
一般常规优化手段
lighthouse
牛x在你的页面上找出一些常规的性能瓶颈,并提出优化建议,例如:
[外链图片转存失败,源站可能有防盗链机制,建议保存图片并直接上传(img-7lsqgX56-1656318262716)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1bcb278a36354d22b442754ba47ecdec~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]
因此,对于这些优化建议,我们需要做一些常规的优化:
- 减少未使用的javascript
- 移除阻塞渲染的资源
- 压缩图片质量
- 限制字体数量,尽量少使用变体
- 优化关键渲染路径:只加载当前页面渲染所需的必要资源,在页面渲染完成后加载次要资源
通用性能优化分析
我们知道lighthouse 有六个性能指标,LCP、 FCP、speed index
、 由于一般情况下,这三个指数尤为重要 这三个指标会受到影响 TTI、TBT、CLS
的分数
所以我们在优化的时候, 需要提高LCP、 FCP和speedIndex 测试后, 即使是空页面也会有时间损失, 初始分数基本都是0.8
秒
注意: 值得注意的是,我们目前所有的测试都是基于的,移动端
(使用移动端的原因是因为pc 在计算能力强的基础上,性能瓶颈很少),页面上必须有内容才能得分。内容必须包括一个或多个
- 内嵌在svg元素内的image元素
- video元素(使用封面图像)
- 通过url()函数(而非使用)CSS 渐变)加载的带有背景图像的元素
- 包含行内文本节点或其他文本元素子元素的块级元素。
否则会出现以下错误
接下来我们就走LCP、 FCP和speedIndex 从这三个指标开始
FCP(First Contentful Paint)
顾名思义就是第一次绘制内容
,也就是说,页面开始绘制内容的时间,但因为我们现在开发的页面是spa因此,框架层面的初始化肯定会有一定的应用性能损耗
的,以vue-cli 以脚手架为例架为例。当我打包并上传空脚手架时cdn部署,FCP 就会从0.8s提上到1.由此可见5秒vue 的diff 也不是免费
他也会有性能损失
在优化页面内容之前,我们声明了三个前提
- 提高FCP的时间其实就是在优化关键渲染路径
- 如果是样式文件(CSS在渲染页面之前,浏览器必须完全分析它(这就是为什么CSS渲染障碍)
- 如果是脚本文件的话(JavaScript浏览器必须:文件) 停止分析,下载脚本并运行它。只有在这之后,它才能继续分析,因为 JavaScript 脚本可以改变页面内容(尤其是HTML)。(这就是为什么JavaScript阻塞解析)
鉴于上述用例测试,我们发现无论我们如何优化,框架本身的性能损失都无法消除。我们唯一能做的就是让框架更早地实施初始化,并且初始化的内容更少。优化方法如下:
- 所有不能初始化的东西js 文件全部走异步加载,也就是加上
defer
或者asnyc
,还有一些需要去cdn第三方插件需要放在页面底部(因为在顶部,他的分析会阻止html 从而影响分析css 等待文件下载,这也是雅虎军规
的一条) - js 文件拆包,以vue-cli 例如,一般来说,我们可以通过cli的配置 splitChunks 做代码分割,拿走一些第三方包cdn,或者拆包。如果有路由,将路由拆包,以确保每条路由只能拆包
加载当前路由js代码
- 优化文件大小 减少字体包,css文件、以及js文件的大小(当然这些) 默认情况下,脚手架已经完成)
- 优化项目结构,每个组件的初始化都有
性能损耗
在保证中可维护性
在此基础上,初始组件的加载量应尽量减少
5.在网络协议层面的优化,这种优化手段需要服务端配合纯前端,目前无法实现云服务器
在盛行的时代,自己的单位通常默认在云服务器中打开这些优化手段,如打开gzip
,使用cdn
等等
其实说来,提高FCP 只有概念之后的两个核心 减少视图内容的初始化
和 减少初始下载资源的大小
LCP(Largest Contentful Paint)
顾名思义就是绘制最大内容
, 何时报告LCP,官员们这么说
浏览器在绘制第一帧后立即分发一个,以应对这种潜在的变化largest-contentful-paint
类型的PerformanceEntry
,用于识别最大内容元素。然而,在渲染后续帧后,浏览器会在最大内容元素发生变化时分发另一个。PerformanceEntry
。
例如,在一个带有文本和第一张图片的网页上,浏览器最初可能只渲染文本部分,并在此期间分发一个largest-contentful-paint/code>条目,其
element
属性通常会引用一个或
。随后,一旦首图完成加载,浏览器就会分发第二个
largest-contentful-paint
条目,其element
属性将引用
。
需要注意的是,一个元素只有在渲染完成并且对用户可见后才能被视为最大内容元素。尚未加载的图像不会被视为"渲染完成"。 在字体阻塞期使用网页字体的文本节点亦是如此。在这种情况下,较小的元素可能会被报告为最大内容元素,但一旦更大的元素完成渲染,就会通过另一个PerformanceEntry
对象进行报告。
其实用大白话解释就是,通常情况下,图片、视频以及大量文本绘制完成后
就会报告LCP
理解了这一点,的优化手段就明确了,尽量减少这些资源的大小就可以了,经过测试,减少首屏渲染的图片以及视频内容大小后,整体分数显著提高,提供一些优化方法:
- 本地图片可以使用在线压缩工具自己压缩 推荐tinypng.com
- 接口中附带图片,一般情况下单位中都有对应的oss或者cdn传参配置通过地址栏传参方式控制图片质量
- 图片懒加载
SpeedIndex(速度指数)
Speed Index
采用可视页面加载的视觉进度,计算内容绘制速度的总分。为此,首先需要能够计算在页面加载期间,各个时间点“完成”了多少部分。在WebPagetest中,通过捕获在浏览器中加载页面的视频并检查每个视频帧(在启用视频捕获的测试中,每秒10帧)来完成的,这个算法在下面有描述,但现在假设我们可以为每个视频帧分配一个完整的百分比(在每个帧下显示的数字)
以上是官方解释的计算方式,其实通俗的将,所谓速度指数就是衡量页面内容填充的速度
一图胜千言
经过测试,跟LCP相同,图片以及视频内容对于SpeedIndex的影响巨大,所有优化方向,通之前一致,总的来说,只要提高LCP 以及FCP 的时间SpeedIndex 的时间就会有显著提高
不过需要注意的是,接口的速度也会影响SpeedIndex的时间,由于AJAX流行的今天,我们大多数的数据都是使用接口拉取。如果接口速度过慢,他就会影响你页面的初始渲染, 导致性能问题,所以,在做性能优化的同时,请求后端伙伴协助,也是性能优化的一个方案
排查性能瓶颈
上述分析,根据三个指标提供了一些常规的优化手段,那么在这些优化手段中,有的你可以立马排查到,并且优化例如:
- 优化图像,优化字体大小
- 跟服务端配合利用浏览器缓存机制.启用cdn、启用gzip等
- 减少网络协议过程中的消耗,减少http 请求、减少dns查询、避免重定向
- 优化关键渲染路径,异步加载js等
但是有的优化手段我们不容易排查,因为他是打在包里面的,这个js 文件包含了很多逻辑怎么办,这里我有两个手段或许能够帮助排查出性能瓶颈发生在哪里:
分析包内容
在通常情况下,我们无法判断的优化点,都是在打包后,我们无法分析出,那些东西不是我们在首屏必须需要的,从而不能做出针对新的优化,为了解决当前问题,各大bundle厂商也都有各自的分析包的方案
以vue-cli 为例
"report": "vue-cli-service build --report"
我们只需要在脚手架中提供以上命令,就能在打包时生成,整个包的分析文件
如上图所示 在打包后就能分析出打包后的js 文件他包含什么组件,如此以来,我们就能知道那些文件是没必要同步加载的,或者走cdn的,通过配置将他单独的隔离开来,从而找出性能的问题
利用chorme devtool 的代码覆盖率
如下图所示,
利用 devtool的代码覆盖率检查就能知道那些js 或者css 文件的代码没有被使用过,结合包内容的分析,我们就能大概的猜出性能的瓶颈在哪里从而做相应的特殊处理
针对vue 的特殊优化
以上内容都是通用的一些优化手段,您在哪都能查到,只是我表达了一下做这些常规优化的深层原因。能让您更清楚的了解这些原因之后,在性能瓶颈的时候能游刃有余,而不是为了面试死记硬背,一到用的时候就不灵
然后我司是vue啊,咱得上得vue 的手段
图片懒加载
所谓图片懒加载,就是页面只渲染当前可视区域内的图片,如此一来,减少了其他图片渲染数量,能大大提高SpeedIndex
和LCP
的时间,从而提高分数
在vue中提起图片懒加载插件,首推vue-lazyload
使用方式简单,功能丰富
虚拟滚动
在一含有长列表页面中,你有没有发现你是往下越滑越卡,此时虚拟滚动就排上用场了, 他的基本原理就是只渲染可视区域内的几条数据,但是模拟出正常滑动的效果,因为每次只渲染可是剧域内的数据,在滑动的时候他的性能就会有飞速提升
在vue中比较好用的插件有两个vue-virtual-scroller和vue-virtual-scroll-list
目前我司统一用的vue-virtual-scroll-list 他下拉的时候到了分页的地方能加些loading提示
vue 中的函数式组件
在vue中我们知道组件的初始化是比较损耗性能的,大家可以去试一下,使用vue 直接渲染一个文字内容,和直接渲染一个app.vue 组件他的分数是略有不同的。
但是当有了函数式组件,这个问题就迎刃而解了
因为函数是组件顾名思义他就是个函数,说白了就是个render函数
,他少了组件初始化的过程,省去了很多初始化过程的开销
什么时候用函数式组件呢?
当你的组件中没有业务逻辑只展示内容时,这时候函数式组件就派上用场了
利用v-show 、KeepAlive 复用dom
我们知道v-show是通过display 控制dom的展示隐藏,他并不会删除dom 而我们在切换v-show的时候其实是减少了diff的对比,而KeepAlive 则是直接复用dom,连diff 的过程都没了,并且他们俩的合理使用还不会影响到初始化渲染。如此一来减少了js 的执行开销,但是值得注意的是,他并不能优化你初始化的性能,而是操作中的性能
分批渲染组件
在前面我们提到过SpeedIndex 的渐进渲染是提高SpeedIndex的关键,有了这个前提,我们就可以分批异步渲染组件。先看到内容,然后在渲染其他内容
举个例子:
{
{ data1 }}
{
{ data2 }}
上述例子比较简单可能描述的不太贴切,在这里特此说明一下,当前方法适用于组件内容较多,每次render 时间过长,导致白屏时间过长,比如,一次拉取用户列表
,那么分批渲染就非常合适,先展示一部分用户信息,最后直到慢慢将所有内容渲染完毕。如此对浏览器的SpeedIndex 也非常友好
最后
性能优化一直是一个很火的话题, 不管从面试以及工作中都非常重要,有了这些优化的点,你在写代码或者优化老项目时都能游刃有余,能提前考虑到其中的一些坑,并且规避。
但是大家需要明白的是,不要为了性能优化而性能优化,我们在要因地制宜
,在不破坏项目可维护性的基础上去优化,千万不要你优化个项目性能是好了,但是大家都看不懂了,这就有点得不偿失了,还是那句话,60分万岁61份浪费,差不多得了
,把经历留着去干更重要的事情!