这里会从影响web性能的各个方面谈性能优化。
浏览器相关
浏览器主要影响的是渲染过程,因此会从渲染的五个阶段入手。
五个阶段即
- parse
- Style calculation
- Layout
- Paint
- Compositing
parse
dom的解析阶段
- 设置script的defer或async,防止阻塞
Style calculation
这个阶段解析cssom,会为每个元素的每个属性对应一个computed value
- 降低选择器复杂度
Layout
这个阶段会计算每个元素的坐标,并生成layout tree。
- dom操作比较耗性能,因此要注意dom的操作
- 减少dom,使用新的盒子模型,比如flex box
- 减少dom修改次数,使用DocumentFragment或虚拟dom,减少dom插入,每次插入都是一次宏任务都会引起页面渲染
- 避免forced synchronous layout造成的卡顿或layout thrashing。一个页面包含两个tree,其中一个表示实际的dom,一个表示内存中被js操作的dom,操作前者很耗费性能,当读取元素样式时会强制元素渲染,即修改实际dom,在执行一系列dom操作时应避免这种情况
compositing
- 利用willchange或transform: translateZ(0)将需要改动的元素分到单独的层,分层本身就消耗性能,不要对过多元素使用
其他
- 不同css属性对后面三步会有不同的影响,详见这里,因此要尽量使用影响比较少的操作,比如修改元素位置时可以使用translate,而不是margin等,这样只会影响合成。
- 节流和防抖
- 用requestAnimationFrame()执行动画或其他耗时短且高优先级的任务
- 低优先级或耗时长的任务可以起一个web worker或使用requestIdleCallback()分成多个小计算完成。
V8相关
V8相关优化的背景知识点看这里
- 按特定顺序添加对象属性(如果是实例一个class,要在构造函数中添加属性),从而共用Shape
- 不要修改array的property attribute,否则需要另外用字典保存对应元素
- 修改原型链会造成ValidityCell,乃至对应inline cache无效,如需要应在其他代码执行前修改
- 防止内存泄漏
网络配置
这部分用来减少网络请求造成的性能问题
- http2
- cdn
- http缓存
- 本地缓存,比如使用rtk query可以直接使用上次相同参数网络请求的结果
webpack
生产配置
- 对于大文件代码分割
- 使用SplitChunksPlugin分割js,MiniCssExtractPlugin分割css,减少单个bundle的体积
- 使用import()或React.lazy()实现动态加载
- 使用import时添加内置指令,输出resource hint,包括prefetch和preload
- 使用external设置lib,将必要依赖的下载交给用户
- 合并小文件,减少http请求,比如在module.rule中的图片文件type设置为配置为
asset
,小图片被转化为base64。 - 压缩文件,使用
mode:production
会使用TerserPlugin压缩js,还可以使用CssMinimizerWebpackPlugin压缩css - tree shaking,利用es module的静态分析,移除没使用的代码,默认会移除export但没使用的模块,使用package.json 的 "sideEffects"属性,可以移除完全是副作用的代码
- 缓存,设置optimization.runtimeChunk: 'single',提取runtime,optimization.moduleIds: 'deterministic'处理moduleid,配合http缓存
- 使用include等指定实际需要处理的模块。
开发配置
开发环境侧重于代码修改后的快速响应。
- cache webpack的dll相关设置已经凉了,取代的是cache选项,默认在内存中缓存,冷启动时比较慢,可以设置缓存在硬盘中,据经验,比不设置cache能快20倍左右。
- 打包时处理更少的文件,比如设置resolve和babel的相关目录
- hmr,模块热更新,保留状态,更快响应,原理
- 编译输出到内存,webpack-dev-middleware