当有人说你页面有性能问题,该怎么办

10,505 阅读5分钟

背景

  • 产品:你看看这页面加载的如此之慢,怎么会有用户用呢?(并甩给了我一个录屏)
  • : (抛出前端应对之策)前端需要加载vue,js,html,css这些都需要时间呀,是不是,别说还需要接口请求,数据库查询,js执行,这些都需要时间是不是,所以加载慢很正常,让用户用wifi嘛。(嗯。。。心安理得,就是这样。。)
  • 产品: 你上一家公司就是因为有你这样的优秀员工才倒闭的吧?!

这么说我就不服了,先看看视频:

我的影片我.gif 掐指一算,也就10s,还。。。。。。。。。。。。好吧,行吧,我编不下去。

前戏

欲练此功,必先自宫。额。。不对。欲解性能,必先分析。 市面上的体检套餐有很多种, 但其实都是换汤不换药. 那药 (标准) 是什么呢? 我们会在下面说明. 这里我选择了谷歌亲儿子 " 灯塔 "(LightHouse) 进行性能体检.

640.webp 从上面中我们可以看到灯塔是通过几种性能指标及不同权重来进行计分的. 这几种指标主要是根据 PerformanceTiming 和 PerformanceEntry API 标准进行定义. 市面上大多体检套餐也是基于这些指标定制的. 接下来我们来了解下这些指标的含义吧.

具体含义

FCP (First Contentful Paint)

First Contentful Paint (FCP) 指标衡量从页面开始加载到页面内容的任何部分在屏幕上呈现的时间。对于此指标,“内容”是指文本、图像(包括背景图像)、<svg> 元素或非白色 <canvas> 元素。

SI (Speed Index)

速度指数衡量页面加载期间内容的视觉显示速度。

LCP (Largest Contentful Paint)

LCP 测量视口中最大的内容元素何时呈现到屏幕上。这大约是页面的主要内容对用户可见的时间.

TTI (Time to Interactive)

TTI 衡量一个页面需要多长时间才能完全交互。在以下情况下,页面被认为是完全交互的:

  • 页面显示有用的内容,这是由 First Contentful Paint 衡量的,
  • 为大多数可见的页面元素注册了事件处理程序
  • 并且该页面会在 50 毫秒内响应用户交互。

TBT (Total Blocking Time)

FCP 到 TTI 之间, 主线程被 long task(超过 50ms) 阻塞的时间之和 TBT 衡量页面被阻止响应用户输入(例如鼠标点击、屏幕点击或键盘按下)的总时间。总和是通过将所有长任务的阻塞部分相加来计算的,即首次内容绘制和交互时间。任何执行时间超过 50 毫秒的任务都是长任务。 50 毫秒后的时间量是阻塞部分。例如,如果 Lighthouse 检测到 70 毫秒长的任务,则阻塞部分将为 20 毫秒。

CLS (Cumulative Layout Shift)

累计布局偏移值

FID (First Input Delay)

衡量您的用户可能遇到的最坏情况的首次输入延迟。首次输入延迟测量从用户第一次与您的网站交互(例如单击按钮)到浏览器实际能够响应该交互的时间。

体检结果

WechatIMG55139.png

哈哈哈,不愧是优秀的前端工程师。。。6项性能指标挂了5个。

手术方案

优化建议

1629886726026_C607FFC4-676D-4245-86DE-385AE0087581.png 那好,我们一个一个的逐个攻破。

减少初始服务器响应时间

下面是我和后端友好的对话:

  • : 你这首页接口2.39s,你是闭着眼睛写的接口吗?
  • 后端大佬: xxx哔哔哔哔哔哔xxxx,想死吗?!******xxxxx哔哔哔哔哔哔哔哔哔哔
  • : 我也觉得是前端的问题,嗯,打扰了。。。 行,下一个优化点。

减少未使用的 JavaScript

经过分析,我发现首页仅涉及到资源请求,并不需要请求库(我们内部封装)的加载,同时依赖的第三方的库也不需要长时间的版本更新,所以并不需要单独打包到chunk-vendors中。 查看基于 webpack-bundle-analyzer 生成的体积分析报告我发现有两个可优化的大产物:

内部封装的请求库需要md5和sha256加密请求,导致包打包出来多了600kb,于是在和领导商议之后决定用axios重写封装。

vue,vuex,vue-router,clipboard,vue-i18n,axios等三方的库上传cdn,首页预加载。

经过优化, bundle 体积 (gizp 前) 由原来的 841kb 减小至 278kb.

WechatIMG55140.png

避免向现代浏览器提供旧版 JavaScript

WechatIMG55141.png 没有想到太好的代替方案,暂时搁置。

视觉稳定性

优化未设置尺寸的图片元素

改善建议里提到了一项优先级很高的优化就是为图片元素设置显式的宽度和高度, 从而减少布局偏移和改善 CLS.

<img src="hello.png" width="640" height="320" alt="Hello World" />

避免页面布局发生偏移

我们产品中header是可配置的, 这个header会导致网站整体布局下移. 从而造成了较大的布局偏移. 跟产品 'qs'交易后, 讲页面拉长,header脱离文本流固定定位在上方。

最大的内容元素绘制

替换最大内容绘制元素

在改善建议中, 我发现首页的最大内容绘制元素是一段文本, 这也难怪 LCP 指标的数据表现不理想了, 原因: 链路过长 - 首页加载js -> 加载语言包 -> 显示文本内用.

于是, 我决定对最大内容绘制元素进行修改, 从而提升 LCP 时间. 我喵了一眼 Largest Contentful Paint API 关于该元素类型的定义, 将 "目标" 锁定到了一个 loading 元素 (绘制成本低: 默认渲染, 不依赖任何条件和判断). 经过我对该元素的尺寸动了手脚后 (变大), 该元素成功 "上位".

其他

除了针对上面几个指标维度进行优化外, 我还做了几点优化, 这里简单提一下:

  • 优化 DOM 嵌套层级及数量
  • 减少不必要的接口请求
  • 使用 translate 替换 top 做位移 / 动画

优化结果

WechatIMG55142.png

哎,优秀呀,还是优秀的前端工程师呀~~~~~hahahhahaha

下一篇文章: 我是怎样解决修改底层代码带来的问题