浅析如何更好的进行性能优化:构建策略、图像策略、分发策略、缓存策略、CSS策略、DOM策略、阻塞策略、回流策略、异步更新策略
主要来源于这篇文章:写给中高级前端关于性能优化的9大策略和6大指标 | 网易四年实践,算是这篇文章的学习笔记。
性能优化:从过程趋势来说,可分为网络层面和渲染层面;从结果趋势来说,可分为时间层面和体积层面。
一、网络层面
网络层面的优化就是让资源体积更小,加载更快。
1、构建策略 —— webpack
减少打包时间:缩减范围、缓存副本、定向搜索、提前构建、并行构建、可视结构
减少打包体积:分隔代码、摇树优化、动态垫片、按需加载、作用提升、压缩资源
(1)缩减范围:配置 include/exclude 缩小 loader 对文件的搜索范围。好处是避免不要的转义,node_modules 目录体积这么大,那得增加很长时间去检索文件。
(2)缓存副本:配置cache缓存Loader对文件的编译副本,好处是再次编译时只编译修改过的文件,未修改过的文件就不需要要随着修改过的文件重新编译了。
(3)定向搜索:配置resolve提高文件的搜索速度,好处是定向指定必须文件路径。若某些第三方库以常规形式引入可能报错或希望程序自动索引特定类型文件都可通过该方式解决。
alias
映射模块路径,extensions
表明文件后缀,noParse
过滤无依赖文件。通常配置alias
和extensions
就足够。
export default {
// ...
resolve: {
alias: {
"#": AbsPath(""), // 根目录快捷方式
"@": AbsPath("src"), // src目录快捷方式
swiper: "swiper/js/swiper.min.js"
}, // 模块导入快捷方式
extensions: [".js", ".ts", ".jsx", ".tsx", ".json", ".vue"] // import路径时文件可省略后缀名
}
};
(4)提前构建:配置DllPlugin将第三方依赖提前打包,好处是将DLL与业务代码完全分离,且每次只构建业务代码。 —— webpack v4+ 已不需要推荐使用该配置。
(5)并行构建:配置Thread将Loader单进程转换为多进程,好处是释放 CPU 多核并发的优势。
(6)可视结构:配置BundleAnalyzer分析打包文件结构,好处是找出体积过大的原因,从而通过分析原因得出优化方案减少构建时间。
(7)分割代码:分割各个模块代码,提取相同部分代码,好处是减少重复代码的出现频率。webpack v4
使用 splitChunks
替代 CommonsChunksPlugin
实现代码分割。
(8)摇树优化:删除项目中未被引用代码,好处是移除重复代码和未使用的代码。摇树优化首次出现于
rollup
,是rollup
的核心概念,后来在webpack v2
里借鉴过来使用。在 webpack
里只需将打包环境设置成生产环境
就能让摇树优化
生效,同时业务代码使用ESM规范
编写,使用import
导入模块,使用export
导出模块。
export default {
// ...
mode: "production"
};
(9)动态垫片:通过垫片服务根据UA返回当前浏览器代码垫片,好处是无需将繁重的代码垫片打包进去。每次构建都配置@babel/preset-env
和core-js
根据某些需求将Polyfill
打包进来,这无疑又增加了代码体积。@babel/preset-env
提供的useBuiltIns
可按需导入Polyfill
。
在此推荐大家使用动态垫片
。动态垫片
可根据浏览器UserAgent
返回当前浏览器Polyfill
,其思路是根据浏览器的UserAgent
从browserlist
查找出当前浏览器哪些特性缺乏支持从而返回这些特性的Polyfill
。
使用html-webpack-tags-plugin在打包时自动插入动态垫片
。
import HtmlTagsPlugin from "html-webpack-tags-plugin";
export default {
plugins: [
new HtmlTagsPlugin({
append: false, // 在生成资源后插入
publicPath: false, // 使用公共路径
tags: ["https://polyfill.alicdn.com/polyfill.min.js"] // 资源路径
})
]
};
(10)按需加载:将路由页面/触发性功能单独打包为一个文件,使用时才加载,好处是减轻首屏渲染的负担。(这个应用就很常见了)
(11)作用提升:分析模块间依赖关系,把打包好的模块合并到一个函数中,好处是减少函数声明和内存花销。作用提升首次出现于
rollup
,是rollup
的核心概念,后来在webpack v3
里借鉴过来使用。
在未开启作用提升
前,构建后的代码会存在大量函数闭包。由于模块依赖,通过webpack
打包后会转换成IIFE
,大量函数闭包包裹代码会导致打包体积增大(模块越多越明显
)。在运行代码时创建的函数作用域变多,从而导致更大的内存开销。
在开启作用提升
后,构建后的代码会按照引入顺序放到一个函数作用域里,通过适当重命名某些变量以防止变量名冲突,从而减少函数声明和内存花销。
在webpack
里只需将打包环境设置成生产环境
就能让作用提升
生效,或显式设置concatenateModules
。
export default {
// ...
mode: "production"
};
// 显式设置
export default {
// ...
optimization: {
// ...
concatenateModules: true
}
};
(12)压缩资源:压缩HTML/CSS/JS代码,压缩字体/图像/音频/视频,好处是更有效减少体积。极致地优化代码都有可能不及优化一个资源文件的体积更有效。
2、图像策略 —— 主要围绕图像类型
做相关处理,同时也是接入成本较低的性能优化策略
。
只需做到以下两点即可。
- 图像选型:了解所有图像类型的特点及其何种应用场景最合适
- 图像压缩:在部署到生产环境前使用工具或脚本对其压缩处理
图像选型
一定要知道每种图像类型的体积/质量/兼容/请求/压缩/透明/场景
等参数相对值,这样才能迅速做出判断在何种场景使用何种类型的图像。
图像策略
也许处理一张图像就能完爆所有构建策略
,因此是一种很廉价但极有效的性能优化策略
。
3、分发策略 —— 主要围绕内容分发网络
做相关处理,同时也是接入成本较高的性能优化策略
,需足够资金支持。
CDN
最大作用。
- 所有静态资源走CDN:开发阶段确定哪些文件属于静态资源
- 把静态资源与主页面置于不同域名下:避免请求带上
Cookie
浏览器缓存
做相关处理,同时也使接入成本最低的性能优化策略
。能显著减少网络传输所带来的损耗,提升网页访问速度,是一种很值得使用的性能优化策略
。 有两种较常用的应用场景值得使用缓存策略
一试,当然更多应用场景都可根据项目需求制定。
- 频繁变动资源:设置
Cache-Control:no-cache
,使浏览器每次都发送请求到服务器,配合Last-Modified/ETag
验证资源是否有效 - 不常变化资源:设置
Cache-Control:max-age=31536000
,对文件名哈希处理,当代码修改后生成新的文件名,当HTML文件引入文件名发生改变才会下载最新文件
二、渲染层面
1、CSS策略
(1)避免出现超过三层的嵌套规则
(2)避免为ID选择器
添加多余选择器
(3)避免使用标签选择器
代替类选择器
(4)避免使用通配选择器
,只对目标节点声明规则
(5)避免重复匹配重复定义,关注可继承属性
2、DOM策略
(1)缓存DOM计算属性
(2)避免过多DOM操作
(3)使用DOMFragment
缓存批量化DOM操作
3、阻塞策略
(1)脚本与DOM/其它脚本
的依赖关系很强:对<script>
设置defer
(2)脚本与DOM/其它脚本
的依赖关系不强:对<script>
设置async
4、回流重绘策略
(1)缓存DOM计算属性
(2)使用类合并样式,避免逐条改变样式
(3)使用display
控制DOM显隐
,将DOM离线化
5、异步更新策略
(1)在异步任务
中修改DOM
时把其包装成微任务
三、优化指标
- 加载优化:资源在加载时可做的性能优化
- 执行优化:资源在执行时可做的性能优化
- 渲染优化:资源在渲染时可做的性能优化
- 样式优化:样式在编码时可做的性能优化
- 脚本优化:脚本在编码时可做的性能优化
- V8引擎优化:针对
V8引擎
特征可做的性能优化
以上内容大多都有用到,具体内容可看作者文章详情。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2018-07-11 原生JS实现Promise
2018-07-11 构造函数模式
2018-07-11 单例模式
2018-07-11 原生JS实现new方法、new一个对象发生的四部、new里面常用的优先级
2018-07-11 svg image标签降级技术
2018-07-11 window.location属性用法及解决一个window.location.search为什么为空的问题
2017-07-11 浅析JS里的Intl对象及常用方法使用介绍