当咱们对dom 进行修改当时候会引起它外观(样式)上的改变时,就会触发回流或重绘。
这个过程本质上仍是由于咱们对 DOM 的修改触发了渲染树(Render Tree)的变化所致使的浏览器
1.根据 HTML 结构生成 DOM 树
2.根据 CSS 生成 CSSOM
3.将 DOM 和 CSSOM 整合造成 RenderTree
4.根据 RenderTree 开始渲染和展现
5.遇到<script>时,会执行并阻塞渲染缓存
因此由此来看 重绘不必定致使回流,回流必定会致使重绘 前面咱们说回流和重绘是会对dom进行修改,会消耗性能,因此咱们要尽量减小回流和重绘的次数。dom
要减小回流和重绘的发生,咱们得知道那些操做会致使,布局
1.改变dom元素的几何属性
常见的几何属性有 width、height、padding、margin、left、top、border 等等。此处再也不给你们一一列举。有的文章喜欢罗列属性表格,但我相信我今天列出来你们也不会看、看了也记不住(由于太多了)。我本身也不会去记这些——其实确实不必记,️一个属性是否是几何属性、会不会致使空间布局发生变化,你们写样式的时候彻底能够经过代码效果看出来。
2.改变dom树的结构
主要指的是增长或减小dom节点,移动等操做。
3.获取一些特定属性的值
当你要用到像这样的属性:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight 时,你就要注意了!性能
“像这样”的属性,究竟是像什么样?——这些值有一个共性,就是须要经过即时计算获得。所以浏览器为了获取这些值,也会进行回流。spa
除此以外,当咱们调用了 getComputedStyle 方法,或者 IE 里的 currentStyle 时,也会触发回流。原理是同样的,都为求一个“即时性”和“准确性”。code
回流比重绘更加消耗性能,付出的代价更高队列
1.避免逐条改变样式,使用类名去合并样式ip
const container = document.getElementById('container') container.style.width = '100px' container.style.height = '200px' container.style.border = '10px solid red' container.style.color = 'red'
将这段代码用 类名去合并get
.basic_style { width: 100px; height: 200px; border: 10px solid red; color: red; } const container = document.getElementById('container') container.classList.add('basic_style')
2.将 DOM “离线”
let container = document.getElementById('container') container.style.display = 'none' container.style.width = '100px' container.style.height = '200px' container.style.border = '10px solid red' container.style.color = 'red' ...(省略了许多相似的后续操做) container.style.display = 'block'
继续用上面的代码来讲明这个问题
const container = document.getElementById('container') container.style.width = '100px' container.style.height = '200px' container.style.border = '10px solid red' container.style.color = 'red'
从这段代码中发生了几回回流与重绘呢?在这里改变了几何属性的有width, height, border。改变颜色的red,因此致使了三次回流和一次重绘,一眼看过去是很正确的,实际上是忽略了浏览器自身:并无那么简单!这段代码实际上只进行了一次回流和一次重绘,为何和咱们开始想的不同呢?由于现代浏览器是很聪明的。浏览器本身也清楚,若是每次 DOM 操做都即时地反馈一次回流或重绘,那么性能上来讲是扛不住的。因而它本身缓存了一个 flush 队列,把咱们触发的回流与重绘任务都塞进去,待到队列里的任务多起来、或者达到了必定的时间间隔,或者“不得已”的时候,再将这些任务一口气出队。所以咱们看到,上面就算咱们进行了 4 次 DOM 更改,也只触发了一次 Layout 和一次 Paint。可是也有例外,由于有的时候咱们须要精确获取某些样式信息,下面这些:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight 这些属性有很强的“即时性”。当咱们访问这些属性时,浏览器会为了得到此时此刻的、最准确的属性值,而提早将 flush 队列的任务出队——这就是所谓的“不得已”时刻。