共计 4421 个字符,预计需要花费 12 分钟才能阅读完成。
随着需要的一直开发,前端我的项目一直收缩,业务提出:你们的首页加载也太慢啦,我都须要 7、8 秒能力看到内容,于是乎主管就让我联结后端开启优化专项,指标是 3s 内展现齐全首页的内容。
性能指标
开启优化时,咱们要清晰的晓得现状和指标,以及咱们采纳什么样的伎俩,通过检测什么指标来查看到优化的过程。
后果指标
依据这个指标,咱们能够抉择一些性能指标,google 提供了基于用户体验的性能指标,如 FCP、LCP、FID、TTI、TBT、CLS 等,也有指标更少新的用户体验量化形式 Web Vitals,只选取 LCP、FID、CLS。
咱们这次次要抉择的指标是 FCP
、LCP
。FCP 示意着用户能最快看到页面内容的工夫,LCP 则是可视区域的最大内容,这两个指标代表着用户实在对于页面快和慢的体验,FCP 在 1.8 秒内,LCP 在 2.5 秒内是比拟好的。
通过 chrome 浏览器 lighthouse 性能可查看的以后页面的后果指标数据,该我的项目首页 LCP 和 FCP 工夫别离为 7.5s、1s,LCP 十分之慢了。
过程指标
FCP
、LCP
是心愿达到的后果,在优化的过程中,咱们须要一些数据来记录到底在哪些方向做的优化能导致一个比拟好的后果,比方申请数量、页面加载工夫、打包总体积 / 入口文件体积、依赖的 cdn 数量、传输资源体积。
无痕模式下通过 chrome 开发者工具 network 记录这些过程指标,以后我的项目首页过程指标:申请(requests)117 个,页面加载工夫(Load)3.79 秒,打包总体积(resources)21.8MB、依赖的 CDN(须要本人点击页面右键查看网页源码去数)25 个 js、7 个 css 资源,传输资源体积(transferred)6.6MB
较多的资源数量、较大的打包体积都导致了页面加载速度变慢。
页面生命周期
首先咱们得晓得页面的生命周期,能力有针对性的去对前端参加的过程进行优化。那么从浏览器地址栏输出 url,到页面渲染进去,次要通过了哪些步骤呢?
- 输出域名后,DNS 域名解析
- 发动 TCP 的 3 次握手
- 建设 TCP 连贯后发动 http 申请
- 服务器端响应 http 申请,浏览器失去 html 代码
- 浏览器解析 html 代码,并申请 html 代码中的资源
- 浏览器对页面进行渲染出现给用户(DOM、CSSOM、渲染树)
在这个过程中,有很多网络、服务器参加的过程,而咱们次要关注前端可能进行的优化,比方应用 DNS 预解析、缓存机制、缩小我的项目编译后 html / css/ js 包资源大小。
通用优化
删除无用代码
这一步实用于所有我的项目,定期的清理掉不须要的代码能防止我的项目无止境的收缩。因咱们我的项目的历史遗留问题,存在一些无用的 cdn 资源、依赖、组件、配置,在页面加载的过程中他们占据了肯定的网络带宽。
无用 cdn 资源
以后业务场景下这些资源都曾经用不到,也无需在页面初始化的时候加载。
性能反复的资源
由不同开发者依据团体标准引入了,两个不同域名但雷同性能的前端异样数据采集的 cdn 资源,只需保留一个依然保护并且举荐应用的即可。
无用依赖
找遍整个我的项目都用不到的依赖
无用申请逻辑
为了测试组件,追随首页发送的申请,但因业务场景不太相符,未真正投入使用
无用文件
可用 webpack 插件 unused-files-webpack-plugin 找到已不须要应用的文件,再通过 nodejs 中内置的文件解决 fs 定义函数将其递归删除。
网络相干
域名收敛
在我的项目中,咱们可能须要加载很多不同的内容,无论是了为了页面更为好看的图片、字体,还是不适宜编译到我的项目中体积较大的 cdn 的资源(如 echarts、谷歌地图)。
咱们晓得通过 http 申请获取资源须要经验 DNS 域名解析、TCP 三次握手、建设 TCP 连贯后发送 http 申请、服务器响应 …. 在这里第一步就是域名解析,如果本地没有缓存,那么这里将会从顶级域名开始一层层往下找,须要消耗很多工夫。
通过域名收敛,将雷同的利用 / 资源整合到同一域名,缩小不同域名之间 DNS 的解析工夫,咱们我的项目资源次要有几大类(xxx 代表公司域名)
- JS、CSS 应用
g.alicdn.com
、assets.xxx.cn
- 图片收敛到文件平台
imgcdn.xxx.cn
,assets.xxx.cn
- 字体图标收敛到
at.alicdn.com
- 非凡如高德地图
webapi.amap.com
之类
DNS 预解析
在执行 js 文件前会存在一些闲暇工夫,能够用来解析 dns 地址,dns 预解析是异步执行的,不会对 html 页面代码造成阻塞,这样在真正加载资源时能够缩小用户的等待时间。
下面曾经将域名进行了收敛,html 中 <link> 元素通过 dns- prefetch 的 rel 属性提供这项性能,而后在 href 属性中指定要跨域的域名(仅作用于与以后页面不一样的域名)。
<link rel="dns-prefetch" href= "//imgcdn.xxx.com">
以上两个步骤别离删除无用的资源和晋升网络连接,和我的项目类型、业务场景关联不大,属于很多我的项目都通用的计划。接下来的步骤须要依据资源编译状况来进行优化。
编译产物优化
在 webpack 配置中减少插件 webpack-analyzer-plugin
,本地运行我的项目,编译后的资源包状况将在在 8888 端口展现。从编译产物中,咱们能够看到每个 js 包原始大小,压缩后尺寸,js 中次要有哪些库,依据这些具体的信息进行优化。
图中 vendor.js 是我的项目打包的入口文件,是第一次关上任意页面都会加载的资源,仔细观察那些体积较大的资源,想方法进行优化。
合并 echarts 版本
从图中能够看到,绘图组件有两个组件库,BizCharts、echarts,而 echarts 还分为 5.4 和 4.9 的版本,并且在 index.html 中还通过 cdn 引入了 4.2.1 版本并且没有应用 externals 排除打包。
找到不同 echarts 版本的组件起源,咱们我的项目中两个版本别离来自 echarts 本身和公司业务组件,还有 react-for-echarts 组件的依赖。
优化计划是找一个各组件都能够应用版本,将 package.json 和 cdn 地址中 echarts 版本与组件库中保持一致(应用 5.3.3 版本),通过 externals 排除打包,这样间接应用 cdn 资源,不再将 echarts 编译至入口文件 vendor.js 中
// index.html
"externals": {"echarts": "echarts"}
另外还有 BizCharts,因为应用到的菜单已下线,所以间接将这部分删除。
loadash 工具缩包
我的项目中常会用到 loadash 之类的工具库,为了应用几个函数将整个工具库的资源都引入十分的不值得,比拟好的形式是只通过 import 引入具体须要应用的文件,如 import _add from 'lodash/fp/add'
。
但很有可能并不是我的项目中的每个人都会恪守这样的规定,如果应用全量引入的形式,如 import _ from 'lodash'
, 导致全量资源被编译至我的项目主入口文件中。
为了防止这种状况,咱们能够应用 babel 插件来 babel-plugin-lodash
将全量引入形式编译成按文件引入。
import _ from 'lodash'
import {add} from 'lodash/fp'
const addOne = add(1)
_.map([1, 2, 3], addOne)
编译成
import _add from 'lodash/fp/add'
import _map from 'lodash/map'
const addOne = _add(1)
_map([1, 2, 3], addOne)
babel-plugin-lodash
是 babel
插件, 在 webpack 中配置到 babel-loader
里
rules: [
{
exclude: /node_modules/,
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: {presets: ['@babel/preset-env'],
plugins: ['lodash'],
},
}],
},
],
咱们我的项目应用的是团体对立脚手架,只暴露出 webpack-chain 的形式去批改,所以是这样应用。
const merge = require('lodash/merge');
config.module
.rule('jsx')
.use('babel-loader')
.tap((options) => {
return merge(options, {plugins: ['babel-plugin-lodash'],
});
});
从图中能够看出 xlsx
资源编译后的体积也十分大,但咱们我的项目以后业务场景已没有应用到,所以间接删除,像低频应用的资源,能够替换成 cdn 链接或者拆包编译并提早引入。
通过以上删除、合并整顿,主入口资源从 7.51M 升高 2.51 M。
devtool
借助 chrome 浏览器的 devtool 来进行进行进一步的解决
lighthouse 倡议
将我的项目关上在 chrome 浏览器中,应用 lighthouse 不仅能够用来检测我的项目 LCP、FCP 评分,还有一些针对以后检测页面的倡议。
点开之后就是每一条具体的倡议,比方提醒存在一些首页用不到的 js、css 资源,为图片减少宽高缩小布局偏移。
首页用不到但其它中央须要应用 js、css 资源能够去除入口 index.html 的引入,改为到指定文件须要应用时再提早加载 cdn 资源。
计划大略是这样:
- 如果指定页面没有加载须要的资源,须要通过 scrpt 标签加载须要的 js 资源,link 标签加载须要的 css 资源
- 判断 cdn 引入的资源已挂载在 window 对象之后,再开始执行页面的渲染
这样每个页面负责本人所须要的资源,无需将所有资源的加载压力都放到首页
network 查看接口响应
性能优化也不是前端致力就足够的,页面加载过程中,后端接口响应速度也很要害,如果后端接口响应过慢,前端拿不到数据也无奈进行渲染。
在咱们我的项目首页中,获取用户菜单权限的接口十分的慢,每次关上页面都须要一秒钟左右能力响应,存在很重大的阻塞问题,反馈给后端同学进行优化后,能放弃在 100-200 毫秒实现响应。
优化后果
通过以上优化,性能过程指标,load 时长、资源体积、依赖 cdn 数量、传输资源体积都有了很大的晋升。
性能后果指标 LCP 放弃在 1 秒,FCP 由 7.5 秒升高至 1.1 秒,页面渲染实现由 8 秒 降到 2 秒左右,达到了我的预期。
优化完还有十分重要的事件就是 肯定要充沛测试! 已上线的需要在进行如此大的改变后,肯定要先自测一遍业务性能是否受影响,再提给测试同学排期对整个我的项目进行测试,等到充沛测试实现能力公布。
总结
攻城容易守城难,做好了一次优化不意味着可能长期的放弃,重要的是全组的同学在平时的需要开发中留神性能做好保护工作,不然资源会像滚雪球一样越来越大,页面的加载速度就在无形之中越来越慢。