前端性能优化总结
性能优化
性能优化主要解决方案:
5点
- 加速或减少HTTP请求损耗:使用CDN加载公用库,使用强缓存和协商缓存,使用域名收敛,小图片使用Base64代替,使用Get请求代替Post请求,设置Access-Control-Max-Age减少预检请求页面内跳转其他域名或请求其他域名的资源时使用浏览器prefetch域解析等。
- 延迟加载:非重要的库、非首屏图片延迟加载、SPA的组件的懒加载等。
- 减少请求内容的体积:开启服务器Gzip压缩,JS,CSS文件的压缩合并,减少cookies的大小,SSR直接输出渲染后的HTML等。
- 浏览器渲染原理:优化关键渲染路径,尽可能减少阻塞渲染的JS,CSS。
- 优化用户等待体验:白屏使用加载进度条、loading图、顾佳屏代替等。
加载相关
为什么强调把css放在header中,js放在尾部?
DOMContentLoaded事件:当纯HTML被完全加载以及解析时,仅仅是DOM加载完成,而不必等待样式表,图片的加载。
load事件: 仅仅在整个页面完全加载完成时被使用。即:页面上所有的DOM,样式表,脚本,图片都加载完成。
构建Render树需要DOM和CSSOM树,所以HTML和CSS都会阻塞渲染。所以需要css尽早加载(放在头部),以缩短首次渲染的时间。
除此之外,由于css不会阻塞文档的解析,但是会阻塞文档渲染。
把CSS放在头部,可以先生成CSSOM树,后续渲染DOM的时候,可以一次性构建Render树,只需要渲染一次;
如果把CSS放在后面,会先解析一次DOM,加载CSS之后,会重新渲染之前的DOM,需要两次渲染。
阻塞浏览器的解析,也就是发现了一个外链脚本时,需等待脚本下载完成并执行后才会继续解析HTML。
普通脚本会阻塞浏览器的解析,加上defer或async属性,脚本就会变成异步,可等到解析完毕后再执行。
- async异步执行,异步下载完毕后就会执行,不确保执行的顺序,一定在onload前,但不确定在DOMContentLoaded事件的前后。
- defer 延迟执行,相当于放在body最后(理论上会在DOMContentLoaded事件的前面)
- 执行js代码过长会卡住渲染,对于需要很多时间计算的代码可以考虑用Web Worker,它可以另开一个线程执行脚本,但不会影响渲染。
Onload & DOMContentLoaded & domready
- load事件触发时,页面上所有的DOM,样式表,脚本,图片都已加载完成。
- domready事件在DOM加载后、资源加载之前被触发,在本地浏览器的DOMContentLoaded事件的形式被调用。
- DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片。
白屏 首屏
白屏
白屏时间是指浏览器开始显示内容的时间,一般认为浏览器开始渲染body或者解析完head标签的时候就是页面白屏结束的时间。
计算方法:IE8-: title后输出一个时间pagestartime;
head结束前 输出一个时间firstpaint。
白屏时间=firstpaint-pagestarttime/performance.timing.navigationStart;
优化
1.加快js的执行速度,比如:无限滚动的页面,可以用js先渲染一个屏幕范围内的东西。
2.减少文件体积。
3.首屏同步渲染html,后续滚屏再异步加载和渲染。
首屏
首屏时间是指用户打开网站开始到浏览器首屏内容渲染完成的时间。
计算方法:
1.模块标签标记。适用于内容不需要拉取数据才能生存以及页面不考虑图片等资源的家在情况,结束位置加时间戳输出时间。
2.统计首屏内图片加载最慢的事件。通常图片加载最慢,所以会把首屏内加载事件最慢的图片时间。
3.自定义计算。
优化
1.首屏数据的拉取逻辑放在顶部(数据最快返回)
2.首屏渲染css及js逻辑优先内联html,返回时能立即执行。
3.次屏逻辑延后执行。
渲染相关
如何减少重绘和回流?
-
使用transform替代top
-
使用visibility替换display:none (因为visibility只会引起重绘,而display:none 还会引起回流 从而会改变布局)
-
不使用table布局,因为可能很小的一个改动会造成整个table的重新布局。
-
CSS选择符从右往左匹配查找,避免节点层级过多。
-
将频繁重绘或者回流的家电设置为图层,图层能够阻止该节点的渲染行为影响别的节点。(will-change属性或者video,iframe标签等)
-
节点属性不要放在一个循环里当循环变量
//每次都要去取正确的值才行 for(let i=0;i<100;i++){ console.log(document.querySeletor('.test').style.offsetTop); }
为什么操作DOM的性能差?
DOM属于渲染引擎中的东西,而js又是js引擎中的东西。当我们通过js操作DOM时,这个操作涉及到两个线程之间的通信,因此一定会带来性能上的损耗。
操作DOM的次数一多,就等同于一直在进行线程之间的通信,并且操作DOM可能会带来重绘回流的情况,因此导致性能上的问题。
插入几万个 DOM,如何实现页面不卡顿?
解决问题的重点在于:如何分批次部分渲染DOM
- 通过requestAnimationFrame的方式循环插入DOM
- 通过虚拟滚动
原理:只渲染可视区域内的内容,非可见区域则完全不渲染,当用户在滚动时就实时去替换渲染的内容。
(即使列表很长,但是渲染的DOM元素永远只有几个,当我们滚动页面的时候就会实时去更新DOM。)
不考虑缓存和优化网络协议的前提下,可以通过哪些方式来最快的渲染页面?
1.考虑文件的大小
2.从script标签使用上考虑async和differ
3.从需要下载的内容是否需要在首屏使用上来考虑
4.从css,html的代码书写考虑
图片优化
图片大小如何优化
1.减少像素点
2.减少每个像素点能够显示的颜色
图片加载如何优化
1.用css代替。
2.用CDN加载,计算出适配屏幕的宽度,然后去请求相应裁剪好的图片。
3.小图片使用base64格式。
4.可以使用雪碧图(将多个图标文件整合到一张图片中)
5.选择正确的图片格式:
- 尽量使用WebP格式。因为WebP格式具有更好的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量。
- 小图片使用PNG,对于大部分图标这类图片,完全可以使用SVG代替。
- 照片使用JPEG