重绘和重排是什么?
重排:当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),然后再将计算的结果绘制出来。
重绘:当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式。
原因
我们只要关心渲染引擎(Rendering engine)和 JS 引擎(JavaScript Interpreter)也可称为 JS 解析器。JS 引擎和渲染引擎是独立实现的,两者通过桥接接口通信。而 DOM 由渲染引擎绘制,所以,当 JS 改变 DOM 结构时,必须通过 Bridge 通知给渲染引擎,然后进行重排或者重绘。这个通信是有开销的。
优化点
重排的开销要远大于重绘
- 尽可能减少 DOM 操作
- 尽可能减少重排
例子
例 1:在 container 元素里面添加 10000 个节点
不好的行为:
- JS 多次读取 DOM 元素
for(var count=0;count<10000;count++){
document.getElementById('container').innerHTML+='<span>hello</span>';
}
- JS 多次更改 DOM 元素
let container = document.getElementById('container');
for(let count=0;count<10000;count++){
container.innerHTML += '<span>hello</span>';
}
好的行为:用 DocumentFragment 容器做内容拼接
let container = document.getElementById('container');
// 创建一个DOM Fragment对象作为容器
let content = document.createDocumentFragment();
for(let count=0;count<10000;count++){
// 通过DOM API创建span
let spanElt = document.createElement("span");
spanElt.innerHTML = 'hello';
// 像操作真实DOM一样操作DOM Fragment对象
content.appendChild(spanElt);
}
// 最后更改DOM
container.appendChild(content)
例 2:更改元素样式
不好的行为:逐条更改样式
const container = document.getElementById('container')
container.style.width = '100px';
container.style.height = '200px';
container.style.color = 'red';
好的行为:
- 只改动一次样式
.basic_style {
width: 100px;
height: 200px;
color: red;
}
//app.js
const container = document.getElementById('container');
container.classList.add('basic_style');
- 当 DOM 离线时(display: none),无论怎么操作,浏览器都不会绘制它,也就不会引发重排或者重绘。
let container = document.getElementById('container');
container.style.display = 'none';
container.style.width = '100px';
container.style.height = '200px';
container.style.color = 'red';
container.style.display = 'block'
注意
需要注意的是,这些属性要慎用,因为这些属性都需要实时计算得到,所以浏览器为了取得正确的值,会进行重排!
offsetTop、offsetLeft、 offsetWidth、offsetHeight、
scrollTop、scrollLeft、scrollWidth、scrollHeight、
clientTop、clientLeft、clientWidth、clientHeight
评论区