前端性能优化
前端性能指标
1.RAIL性能模型
Response、Animation、Idle、Load
FCP(First Content Paint)
即首次内容绘制(文字、图片、非白色Canvas、svg等)所需要的时间。
LCP(Largest Content Paint)
即充满可视区域的内容加载所需要的时间。
FID(First Input Delay)
首次输入延迟,即用户第一次与页面交互到浏览器实际能够响应的时间。
TTI(Time to Interactive)
持续可交互时间,即网页第一次完全到达可交互状态的时间点。
TBT(Total Block Time)
总阻塞时间,即
FID
到TTI
之间的时间。CLS(Cumulative Layout Shift)
累计布局位移,
CLS
会测量在页面整个生命周期中发生的每个意外的布局移位的所有单独布局移位分数的总和,他是一种保证页面的视觉稳定性从而提升用户体验的指标方案。
2. Web-Vitals
缩减为: LCP
、FID
、CLS
一、页面渲染篇🎆
1. 减少页面重绘与回流
- ✨减少css属性简写,如:用
flex-grow
,flex-shrink
,flex-basis
代替flex
,因为css简写将所有值初始化为initial
- ✨通过修改
className
批量修改元素样式 - ✨复杂动画元素定位设置为
fixed/absolute
,避免引起回流 - ✨避免使用
table
布局,因为一旦回流会导致table
所有元素回流 - ✨创建多个DOM节点,使用
DocumentFragment
一次创建 - ✨CSS3硬件加速,使用
transform
/opacity
/filter
等动画不触发回流重绘 - ✨尽量定义高度或最小高度,否则页面内容动态加载的时候,会出现页面元素的晃动或位置的变化,引起回流
- ✨大量修改元素样式的时候,可以先设置
display:none
隐藏,修改完后再设置为display:block
2. 图片压缩、分割
- 🎈压缩图片大小(tinyPng)
- 🎈图片分割,将一张图片分割成多分,最后使用CSS拼接
- 🎈雪碧图(精灵图🧝),将多张图片合成一张图片,使用CSS
background-position
定位图片并且展示。
3. 字体压缩
font-spider🕷
提取所需的字体加载(按需加载)
4. 懒加载/预加载
🎉懒加载:只有当图片到达视窗再进行加载
🎉预加载:Resource Hints(资源预加载)包括预连接、资源与获取、资源预渲染等
实现方式:懒加载与预加载
二、打包优化篇🎇
1. resolve
// vite.config.ts
import {defineConfig} from 'vite';
export default defineConfig({
// ...
resolve: {
extensions: ['.ts', '.js'],
alias: {
'@': './src',
}
}
});
// vite.config.ts
import {defineConfig} from 'vite';
export default defineConfig({
// ...
resolve: {
extensions: ['.ts', '.js'],
alias: {
'@': './src',
}
}
});
alias
- 配置别名
- 每个模块的路径都需要进行解析,解析是比较耗时的,使用别名的时候,打包工具会直接按照别名对应的路径映射过去,提高了打包速度
extensions
当引入方式为:
import('@/data')
,vite
会自动根据extensions
里的顺序依次查找后缀,本示例中会优先找data.ts
,若找不到则找data.js
若还是找不到就报错。因此,extensions
要尽量按照出现频率优先排序,并且不要把项目中不存在的后缀引入extensions
中,引入的时候可以考虑带上后缀。
2. Webpack缩小loader范围
配置loader
的时候,通过include
和except
缩小loader
的执行范围。
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/icons')]
}
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/icons')]
}
3.chunks分包打包
// vite.config.ts
// 自定义分包
import { defineConfig } from 'vite';
export default defineConfig({
build: {
rollupOptions: {
output: {
// key为自定义的名称,[]中插件同步package.json的名称或者src目录下的相对路径
manualChunks: {
vue: ['vue', 'vue-router', 'pinia', 'vue-i18n'],
echarts: ['echarts'],
lodash: ['loadash']
...
}
}
}
}
})
// vite.config.ts
// 自定义分包
import { defineConfig } from 'vite';
export default defineConfig({
build: {
rollupOptions: {
output: {
// key为自定义的名称,[]中插件同步package.json的名称或者src目录下的相对路径
manualChunks: {
vue: ['vue', 'vue-router', 'pinia', 'vue-i18n'],
echarts: ['echarts'],
lodash: ['loadash']
...
}
}
}
}
})
分包的好处:
当我们访问一个页面的时候,如果不进行分包,我们将发送一次HTTP请求获取整个页面的包,此时一个包大小可能很大,请求所需要的时间可能很长;当我们分包构建的时候,只有当需要时,才会对对应的包进行动态请求,这样,能够避免发起请求以及使用额外的带宽。
不仅如此,分包构建后不同的包会根据包的内容计算hash
值,如果某个包内容没有变化,他的hash
值也不会改变,这样浏览器就能够直接从缓存
中获取所需的包,从而节省了网络请求时间和带宽。而对于改变了内容的部分,由于其hash值已经发生了变化,浏览器无法从缓存中获取,需要重新发起网络请求获取最新的资源。这样既保证了网站的实时性,又减少了不必要的网络请求,提高了页面的加载速度和用户体验。
4. Tree Shaking
Tree Shaking
是指在打包时,将未被引用的模块代码剔除掉,从而减小最终打包后的文件大小。Tree Shaking
依赖于 ES6 的模块系统和静态语法分析,可以在编译阶段分析出哪些模块没有被使用,然后在打包时将这些模块移除。Tree Shaking
通过去掉没有使用的代码,从而减小了最终打包文件的体积,提高了应用的加载速度。
Tree Shaking 与 按需导入的区别:
按需导入
是指只加载当前需要的模块,而不是将整个模块全部加载进来。按需导入通常用于优化页面加载速度。例如,在一个大型应用中,可能存在某些功能只在特定情况下才会被使用,这时候可以使用按需导入,只在需要使用时加载对应的模块,减小了应用的启动时间和加载时间。 按需引入相当于选择需要引入的模块或者代码片段,而Tree Shaking 是通过静态分析代码中的依赖关系,自动地将代码中没有使用的部分删除掉,以减小打包后的文件体积。