前端性能优化总结
1. 性能优化方案
1.1 请求优化
1.1.1 请求前
合理利用缓存
- 本地存储:localStorage,indexedDB等本地存储方案
- 浏览器内存缓存
Memory Cache - Service Worker和Cache API,拦截请求,查看是否有缓存,提供的缓存可以认为是“永久性”的,关闭浏览器或离开页面之后,下次再访问仍然可以使用
- HTTP强缓存disk cache(硬盘缓存),Expires 设置过期时间和 Cache-Control设置max-age
- 协商缓存,先“问一问”服务器资源是否过期,过期了返回200,没过期返回304,Last-Modified&If-Modified-Since, ETag&If-None-Match(一般会文件的 MD5 作为 ETag )
- HTTP2的Push Cache:匹配上就用,就不会额外检查资源是否过期;存活时间很短(Chrome 中为 5min 左右);只会被使用一次;连接断开就失效,
server push缓存那些资源
DNS预解析
DNS预解析(dns-prefetch),预建立链接(preconnect),预加载(prefetch,prerender(chrome已弃用),preload立即获取)
减少不必要的请求
浏览器对同源请求的并发限制(chrome是6个),以及TCP的拥塞控制的慢启动特点,考虑请求合并或者按需加载,比如雪碧图,base64 1.3倍,路由懒加载,图片懒加载等,弱网情况下
1.1.2 请求中
-
避免不必要的重定向(301永久重定向,302临时重定向),eg:jd.com -> www.jd.com -> www.jd.com
-
使用http2,二进制分帧,多路复用,头信息压缩,服务器推送,请求优先级
1.1.3 请求后
a. 渲染优化
避免强制同步布局,减少重排,重绘
- 有一些 JavaScript 操作会导致浏览器需要提前执行布局操作,这种操作就被称为“强制同步布局”,如添加元素,删除元素,修改大小,移动元素位置,获取元素相关信息等
- 业务无关脚本使用 async,例如统计脚本、监控脚本、广告脚本等,无外部依赖,不访问DOM,无执行时机限制。(defer)
- 使用文档碎片,批量化操作
- 动画使用requestAnimationFrame更加流畅
- 使用composite合成层:设置3D或者css3 transform,z-index,opacity,filter,开启合成层,合成层由GPU合成,重绘时只会重绘当前层,需要注意
层爆炸,虽然有浏览器的层压缩机制,但是也有很多无法进行压缩的情况,这就可能出现层爆炸的现象。解决方案:使用3D硬件加速提升动画性能时,最好给元素增加一个z-index属性,人为干扰合成的排序,可以有效减少创建不必要的合成层,提升渲染性能,移动端优化效果尤为明显。
b. 服务端渲染
优点:更好的SEO,更快的首屏加载速度 缺点:增加服务器计算压力
c. 静态资源优化
- 使用CDN加速,dns解析返回负载均衡服务器IP,根据本地IP返回最近的负载最低的缓存服务,如果缓存服务器有资源就返回,没有资源就向源服务器请求,并缓存
- 减少包体积: 资源压缩,合并,gzip压缩,tree-shaking,splitChunks提取公共代码(需注意提取粒度),http2头部压缩
- 图片:
a. 选择合适的图片类型
- jpg:有损压缩、体积小、加载快、不支持透明,有锯齿感。使用场景:复杂的、色彩丰富的图片,比如:背景图、轮播图,banner图。
- png:无损压缩、质量高、体积大、支持透明,使用场景: 线条感较强、颜色简单且对比强烈的图片,如logo
- webp:体积小,支持半透明,压缩比更好,兼容性差,使用时需注意图片存储到本地的场景
- base64:减少http请求次数,体积大,增加渲染成本,使用场景:icon
- svg:矢量图、体积小、不失真、兼容性好、渲染成本高,使用场景:icon
- canvas:定制性强,适合动态渲染,大数据绘制
- gif:适合动画,不支持透明,不适合存储彩色图片,(静音的video性能比gif好)
- 字体图标,矢量图,不失真,体积小,使用方便,使用场景:icon
b. 避免空src图片,因为也会发起请求
c. img标签设置alt属性
d. 不同环境下加载不同尺寸和像素的图片,使用media媒体查询或者srcset和sizes属性
e. 较大的图片考虑使用渐进式,先加载缩略图
f. 雪碧图
g. 尽量使用css3代替图片
h. 懒加载和预加载
1.2 框架优化(React)
-
组件更新优化:PureComponent & React.memo(hoc返回PureComponent),usememo & usecallback,useRef
-
immutable:解决PureComponent浅比较的问题,可以很快速的进行深比较
-
reselect优化redux:组件依赖redux中的部分状态没更新,组件就不会更新,react-router-dom中的userSelector用闭包缓存结果实现这个功能
-
Error Boundaries
-
精确的依赖收集,和更新他的子组件
1.3 webpack打包优化
压缩,tree-shaking,提取公共代码块 splitChunks,import()懒加载,预加载proload(同步),文件缓存(hash文件名),happypack
1.4 用户体验优化
- 骨架屏
- 占位图
- 离线缓存
webview冷启动,预请求,loading
1.5 特殊场景优化
- 大数据渲染
- 虚拟列表:使用 position: absolute配合transform: translate3d() 来解决,手动设置展示元素的偏移量。相当于是不断改变这渲染的元素的位置属性和内部的一些节点,不会有频繁的 DOM 创建与销毁
- CPU 密集型任务优化:时间切片requestIdleCallback,并行计算Web Worker启用并行线程处理任务
-
防抖&节流
-
Passive event listeners,通过addEventListener监听事件时,第三个特性设置{passive:true},来阻止默认事件,低版本浏览器第三个参数是用来设置是否进行事件捕获的,所以需要考虑兼容性。
1.6 代码层面优化
- 异常未捕获,导致页面崩溃
- async await 的不当使用导致并行请求变成了串行请求
- 闭包导致的内存泄漏
- 频繁地 JSON.parse 和 JSON.stringify 处理大对象,复杂的是O(n), fast-json-stringfy,提前通过 JSON Schema 知道每个字段的类型
- CPU 密集型任务导致事件循环 delay 严重
- 正则表达式的灾难性回溯,回溯次数过多,就会导致灾难性回溯,CPU 100%
- 注意程序局部性,比如二维数组的行遍历和列遍历的性能差别
- 降低css选择器的复杂性,使用flex布局
1.7 根据具体页面的性能瓶颈,合理选择优化方案
2. 性能监控方案
本地性能测试,lighthouse
用户侧性能监控,RUM (Real User Monitoring)