什么是重流||重绘?
通常页面在加载你的js,css,img等文件时,引擎会对文件加以解析,最终生成两棵树,渲染树和DOM树。DOM树中的需要显示节点在渲染数中都会存在(即display:none的不存在)。DOM是页面显示的HTML结构,渲染树是DOM显示的真实结点 ,也可以理解为渲染树其实就是css文件指定节点的样式表。
- 当渲染树和DOM树都已经完成的时候,则开始将页面显示到桌面上。
如果改变页面的DOM结构,渲染树和DOM树都发生改变
浏览器会重新计算出渲染树的这一过程叫重流(重排)
将更新后的结构重新渲染到页面的这一过程叫重绘
整个流程就是这个图
重流重绘发生的情况
重流发生情况:
- 添加或删除可见DOM元素
- 元素位置改变
- 元素尺寸改变
- 元素内容改变
- 页面渲染初始化
- 浏览器窗口尺寸改变
总的来说,改变页面布局、大小,都会发生重流的情况。那重绘什么时候发生呢?发生重流就一定会发生重绘,但是重绘的范围大一点。比如,当你仅仅改变字体颜色,页面背景等比较“肤浅”的操作时,是不会打扰到重排的。
优化你的DOM
优化DOM的本质其实就是减少DOM树的重绘与重流。
优化DOM的结构,无非就是引用保存,动画优化,节点保存,更新节点等基本操作。
先来看看优化DOM的效果
var times=10000;
var time1 = function(){
var time = times;
while(time--){
//DOM的两个操作放在循环内
var dom = document.querySelector("#Div1");
dom.innerHTML+="a";
}
};
var time2=function(){
var time = times,
dom = document.querySelector("#Div1");
while(time--){
//DOM的一个操作放在循环内
dom.innerHTML+="a";
}
};
var time3=function(){
var time = times,
dom = document.querySelector("#Div1"),
str = "";
while(time--){
//循环内不放置DOM的操作
str +="a";
}
dom.innerHTML=str;
}
console.time(1);
//设置时间起点
time1();
console.timeEnd(1);
console.time(2);
//设置时间起点
time2();
console.timeEnd(2);
console.time(3);
//设置时间起点
time3();
console.timeEnd(3);
//测试结果为:
1: 101.868ms
2: 101.560ms
3: 13.615ms
过多的DOM操作时,一定要保存获取到的DOM节点及所有涉及DOM相关的操作。
合并DOM的操作
div.style.color="red";
div.style.border="1px solid red";
浏览器会聪明的将两次重排合并到一次发生,节省资源。
但是如果中间访问了其他属性等,那么就会再次重排。
div.style.color="red"; //积累一次重排记录
var height = div.clientHeight; //触发重排
div.style.border="1px solid red"; //再次积累一次重排
所以如果更改DOM结构最好一次性写完
CRUD的操作
比如我们要批量的增加子节点的时候,可以使用fragment这个虚拟片段来做一个容器
var times = 100;
var addP = function(){
var time = times,
tag1 = document.querySelector('#tag1');
while (time--) {
var p = document.createElement('p');
tag1.appendChild(p);
}
}
var useFrag = function(){
var time = times,
tag1 = document.querySelector('#tag1'),
frag = document.createDocumentFragment();
while (time--) {
var p = document.createElement('p');
frag.appendChild(p);
}
tag1.appendChild(frag);
}
console.time(1);
addP();
console.timeEnd(1);
console.time(2);
useFrag();
console.timeEnd(2);
//基本事件差为:
1: 1.352ms
2: 0.685ms
除了使用fragment片断,还可以使用innerHTML,outerHTML进行相关的优化操作。
UI操作的优化
最重要的就是absolute排版。因为当你进行UI操作的时候,毫无疑问有可能不经意间导致全屏的渲染(最差的就是整版重排)。
如果使用了absolute进行布局,脱离了文档流,防止页面的过度重排。