性能优化
这是一个比较大的话题.包含了很多部分.总体来讲就是尽量快的加载页面,使用资源又尽量少.
从输入网址到页面渲染,发生了啥
这道面试题就比较宽范的触及到性能优化的各个点.需要比较系统的去理解.
阻塞渲染
想要首屏优化,就得先把页面渲染出来,什么会阻塞渲染呢?
HTML 和 CSS 会,因为他们要合成渲染树.所以就要降低要渲染的文件大小,扁平层级,优化选择器.
还有一个问题,script
会暂停 DOM 渲染.所以一般script
会放在 body 后面.
不想放底部就可以使用defer
和async
属性.两个都是异步下载,和 dom 并行.区别就是执行了.
下载是没区别的.defer
:要等到 DOM 执行完,再按照顺序执行.async
: 下载完就执行,不按顺序,谁先完事谁先跑.
为什么操作 DOM 慢
dom 属于渲染引擎,js 属于 js 引擎,通过 js 操作 dom 就涉及到两个线程之间的通信,就会带来性能损耗.还有可能带来回流重绘的情况,导致性能问题.
插入几万个 DOM,如何实现页面不卡顿
肯定不能一次性加载,需要分批次加载.
方法一: 通过requestAnimationFrame
的方式循环插入 DOM.
方法二: 虚拟滚动.只渲染可视区域的内容.当用户滚动,实时替换渲染的内容.避免空白记得加上预渲染.
HTML 优化
就是在不考虑,网络和缓存的情况下,如何加快渲染?
- 从文件大小考虑
- 从 script 标签使用上来考虑
- 从 CSS、HTML 的代码书写上来考虑
- 从需要下载的内容是否需要在首屏使用上来考虑
图片懒加载
html 实现
给图片加上loading=‘lazy’
1 | <img src'./a.png' loading='lazy' /> |
JS 实现懒加载
原理:拿到所有图片的 DOM,遍历每个图片是否到了可视区域,到了就设置 src 属性,绑定scroll
事件进行事件监听。
1 |
|
intersectionObserver
Intersection Observer 即重叠观察者,从这个命名就可以看出它用于判断两个元素是否重叠,因为不用进行事件的监听,性能方面相比 getBoundingClientRect 会好很多
目标元素与视口产生交叉区域。
IntersectionObserver 是浏览器原生提供的构造函数,接受两个参数:callback 是可见性变化时的回调函数,option 是配置对象(该参数可选)。
目标元素的可见性变化时,就会调用观察器的回调函数 callback。callback 一般会触发两次。一次是目标元素刚刚进入视口(开始可见),另一次是完全离开视口(开始不可见)。
1 | const imgs = document.querySelectorAll("img[data-src]"); |
JS 性能优化
CSS 性能优化
问题: css 层级设置过多导致性能减弱
1 | <div> |
明显第一种要比第二种效率高得多.减少了因查找递归的过程带来的性能损失.
防范: 尽量避免写过于具体的 CSS 选择器,对 HTML 尽量减少无意义的标签.
回流(reflow)和重绘(repaint)
- 回流: 回的是文档流,都要快加载好了,又倒回去了.就是回流.布局或者几何属性发生的变化.
- 重绘: 重新绘画,就是上色.就是外观发生的变化.
- 回流肯定重绘,重绘不一定回流.
1、添加、删除元素(回流+重绘)
2、隐藏元素,display:none(回流+重绘),visibility:hidden(只重绘,不回流)
3、移动元素,如改变 top、left 或移动元素到另外 1 个父元素中(重绘+回流)
4、改变浏览器大小(回流+重绘)
5、改变浏览器的字体大小(回流+重绘)
6、改变元素的 padding、border、margin(回流+重绘)
7、改变浏览器的字体颜色(只重绘,不回流)
8、改变元素的背景颜色(只重绘,不回流)
减少
- CSS 选择符从右往左匹配查找,避免节点层级过多
- 不要使用 table 布局
- 不要把节点的属性值放在一个循环里当成循环里的变量
- 使用
visibility
替换display: none