前言
风和日丽: 我正笑嘻嘻地抓着我炫酷的ikbc键盘疯狂的敲着Bug.
晴天霹雳: 被拉进了一个群,产品说我做的网站很卡,须要做性能优化.
难以置信: 我可是用尊贵的Vue3+Ts开发的呢 (手动狗头).
非常抗拒: 迫于yin威,我给网站做了体检和手术.
体检
市面上的体检套餐有很多种,但其实都是换汤不换药.那药(规范)是什么呢?咱们会在上面阐明.这里我抉择了谷歌亲儿子"灯塔"(LightHouse)进行性能体检.
体检标准
为什么我说大多体检套餐都是换汤不换药呢?咱们先从灯塔的计分规定说起:
从下面中咱们能够看到灯塔v6/v7版是通过几种性能指标及不同权重来进行计分的.这几种指标次要是依据PerformanceTiming和PerformanceEntry API规范进行定义.市面上大多体检套餐也是基于这些指标定制的.接下来咱们来理解下这些指标的含意吧.
FCP (First Contentful Paint)
渲染第一个元素(文本、图片、canvas...)的工夫点
SI (Speed Index)
首屏展示工夫
LCP (Largest Contentful Paint)
渲染可视区域内最大内容元素的工夫点
TTI (Time to Interactive)
页面资源加载胜利并能响应用户交互的工夫点
TBT (Total Blocking Time)
FCP到TTI之间,主线程被long task(超过50ms)阻塞的工夫之和
CLS (Cumulative Layout Shift)
累计布局偏移值
FID (First Input Delay)
用户第一次在页面进行交互(点击链接、按钮、自定义js事件),到浏览器理论开始解决这个事件的工夫
Core Web Vitals
谈到用户体验与性能指标,顺便提下Core Web Vitals.
2020年5月,Google针对网站应用体验推出了一套外围指标规范(Core Web Vitals).由三项指标形成:
为什么不是别的指标呢 ? 因为这套规范次要从以下三个维度进行评估:
- [加载状况] : LCP
- [交互性] : FID
[视觉稳定性] : CLS
如何检视Core Web Vitals 指标 ?
开发者可利用以下几种工具对Core Web Vitals进行监测:
因为FID须要一个实在用户的交互,所以无奈用试验数据测试.为了能在试验数据下测试FID,通常会用TBT (Total Blocking Time).尽管他们测量的内容不同,但改善TBT通常也能改善FID.
体检后果
不检不晓得,一检吓一跳.6个"重要器官"凉了一半...是时候对它动个手术了!
指标评分
改善倡议
手术
手术计划
既然是性能手术,计划就次要以性能指标作为维度,次要分为以下几个点:
- 视觉稳定性 (Cumulative Layout Shift)
- 加载状况 (Largest Contentful Paint)
- TTI (Time to Interactive)
- TBT (Total Blocking Time)
- FCP (First Contentful Paint)
手术过程
视觉稳定性 (Cumulative Layout Shift)
优化未设置尺寸的图片元素
改善倡议里提到了一项优先级很高的优化就是为图片元素设置显式的宽度和高度,从而缩小布局偏移和改善CLS.
<img src="hello.png" width="640" height="320" alt="Hello World" />
自定义字体文件加载期间放弃可见状态
改善倡议里提到应用CSS font-display属性确保自定义字体文件在加载期间可见.
这是因为网站下载自定义字体文件须要一段时间,而不同浏览器此时的行为是不同的.一些浏览器在加载自定义字体时会暗藏文字,这种称之为FOIT(Flash Of Invisible Text).而一些浏览器会显示降级字体,这种状况称之为FOUT(Flash Of Unstyled Tex).这两种行为会导致"字体闪动问题",影响视觉稳定性 (CLS).
我的解决办法是间接设置font-display:swap;这个属性能确保字体在加载工夫可见.尽管还是会引发FOUT,然而相比FOIT,FOUT对视觉稳定性的影响会小一些.
更好的计划应该是预加载(preload)字体文件.让字体下载有更高概率赶在FCP之前,从而防止FOIT/FOUT.
@font-face { font-family: 'Hello-World'; src: url('../font/Hello-World.otf') format('OpenType'); /* swap:如果设定的字体还未可用,浏览器将首先应用备用字体显示,当设定的字体加载实现后替换备用字体 */ font-display:swap; }
- 防止页面布局产生偏移
咱们产品中有一个顶部动静插入的元素,这个元素会导致网站整体布局下移.从而造成了较大的布局偏移.跟产品及ui py交易后,咱们敌对地对这个元素进行了调整.将该元素脱离文档流,采纳固定定位的形式进行展现.从而解决该问题.
- 防止非合成动画
改善倡议中提到应防止应用非合成动画,非合成动画会使得页面变得凌乱并减少CLS.对于这个优化倡议我感觉应该具体场景具体分析,不应该"因噎废食".毕竟目前能被composited的css属性只有transform & opacity.当然这也在揭示咱们平时在做CSS动画时应留神优化 (比方常见的应用transform代替top).
加载状况 (Largest Contentful Paint)
替换最大内容绘制元素
在改善倡议中,我发现网站的最大内容绘制元素是谷歌地图中的一个图块元素.这也难怪LCP指标的数据体现不现实了,起因: 链路过长 - 下载谷歌地图Js sdk => 初始化谷歌地图=> 绘制 .
于是,我决定对最大内容绘制元素进行批改,从而晋升LCP工夫.我喵了一眼Largest Contentful Paint API 对于该元素类型的定义,将"指标"锁定到了一个loading元素 (绘制成本低: 默认渲染,不依赖任何条件和判断).通过我对该元素的尺寸动了手脚后(变大),该元素胜利"上位".
TBT (Total Blocking Time) / TTI (Time to Interactive)
异步加载谷歌地图Js sdk
原先加载谷歌地图Js sdk是通过动静增加script标签同步加载的.这样做的毛病其实是很显著的:- Google Maps Js sdk 加载机会太晚,影响TTI体现和用户体验.
- js引擎占据主线程进行相干js执行.
我的解决计划就是对谷歌地图Js sdk进行异步加载.这里须要留神的是script async/defer的区别,我应用的是defer进行异步加载(async加载结束后会立刻执行,阻塞主线程,影响DOM解析).
<script src="//maps.googleapis.com/maps/api/js" type="text/javascript" defer></script>
- 优化构建bundle体积
查看基于webpack-bundle-analyzer生成的体积剖析报告我发现有两个可优化的大产物: lottie动画库
站点只有一个动画成果的实现用到该库,跟产品、ui又一顿py后,咱们决定就义一点"视觉效果".移除lottie library,改用CSS3实现.
ant-design-vue中内置的momentjs依赖
momentjs的语言包(locale)体积十分大,而站点并无国际化需要.所以这里我间接应用webpack IgnorePlugin对语言包进行疏忽.
通过优化,bundle体积(gizp前)由原来的1.8MB减小至1.3MB.
FCP (First Contentful Paint)
网站应用的是Vue做的客户端渲染.这也意味着FCP过程会有点"漫长". (初始化Vue实例等一系列工作须要占用主线程执行Js).这里我"自作聪明"地在html文件增加了"通明文本占位符",抢占FCP工夫.这个骚操作我集体认为有点抖伶俐,大家能够选择性忽视...
<div id="app"> <!-- 占位符 --> <p style="color:#fff;">Hello World</p></div>
其余
除了针对下面几个指标维度进行优化外,我还做了几点优化,这里简略提一下:
- 优化DOM嵌套层级及数量
- 缩小不必要的接口申请
- 应用translate替换top做位移/动画
手术后果
说了那么多"废话",那手术后果到底如何呢 ? 是富丽变身还是"反向一Q日神仙"呢 ? 间接上图:
通过上图咱们能够看到各项指标及评分都有质的飞跃,尽管我"不要脸地截了个最高分" (LightHouse每次评分会有稳定,实际效果是由原来的50-70分涨到了70-90分) !!!
结语
平时咱们娓娓而谈的性能优化点往往也是咱们最容易疏忽的点.性能优化也绝非欲速不达,须要咱们在日常开发中一直去发现和优化.路漫漫其修远兮...
如果你感觉我的文章对你有帮忙,欢送关注我一起游玩~