根据浏览器渲染引擎工作原理(reflow/repaint),来优化DOM的操作

Posted liuhp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了根据浏览器渲染引擎工作原理(reflow/repaint),来优化DOM的操作相关的知识,希望对你有一定的参考价值。

1.浏览器的渲染引擎工作原理:

  (1)解析html,生成DOM树。解析HTML文档,转换树中的html标签或js生成的标签到DOM节点,它被称为 -- 内容树。

  (2)构建渲染树,解析Style,生成Style Rules,解析CSS(包括外部CSS文件和样式元素以及js生成的样式),根据CSS选择器计算出节点的样式,创建另一个树 —- 渲染树。

  (3)根据(1)和(2)开始布局渲染树,从根节点递归调用,计算每一个元素的大小、位置等,给每个节点所应该出现在屏幕上的精确坐标。

  (4)一旦布局渲染树结束后,接下来浏览器会将其绘制出来,遍历渲染树,每个节点将使用UI后端层来绘制。

   下图是工作原理截图:

技术分享图片

2.重绘与回流(Repaint/Reflow)

repaint(重绘) :repaint发生更改时,元素的外观被改变,且在没有改变布局的情况下发生,如改变outline,visibility,background color,不会影响到dom结构渲染。
reflow(渲染):与repaint区别就是他会影响到dom的结构渲染,同时他会触发repaint,他会改变他本身与所有父辈元素(祖先),这种开销是非常昂贵的,导致性能下降是必然的,页面元素越多效果越明显。

3.引起reflow/repaint的操作

Reflow 的成本比 Repaint 的成本高得多的多。DOM Tree 里的每个结点都会有 reflow 方法,一个结点的 reflow 很有可能导致子结点,甚至父点以及同级结点的 reflow。在一些高性能的电脑上也许还没什么,但是如果 reflow 发生在手机上,那么这个过程是非常痛苦和耗电的。
所以,下面这些动作有很大可能会是成本比较高的。

(1)当你增加、删除、修改 DOM 结点时,会导致 Reflow 或 Repaint。
(2)当你移动 DOM 的位置,或是搞个动画的时候。
(3)当你修改 CSS 样式的时候。
(4)当你 Resize 窗口的时候(移动端没有这个问题),或是滚动的时候。
(5)当你修改网页的默认字体时。
(6)读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、 scrollTop/Left/Width/Height、clientTop/Left/Width/Height、 getComputedStyle()、currentStyle(in IE)

注:display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,因为没有发现位置变化。

4.如何避免

(1)避免一系列的连续操作

demo1

如果需要创建多个DOM节点,可以使用DocumentFragment创建完后一次性的加入document   
var fragment = document.createDocumentFragment();
fragment.appendChild(document.createTextNode(‘keenboy test 111‘));
fragment.appendChild(document.createElement(‘br‘));
fragment.appendChild(document.createTextNode(‘keenboy test 222‘));
document.body.appendChild(fragment);

demo2

//先创建文档碎片
var oFragmeng = document.createDocumentFragment();
for(var i=0;i<10000;i++)
{
var op = document.createElement("span");
var oText = document.createTextNode(i);
op.appendChild(oText);
//先附加在文档碎片中
oFragmeng.appendChild(op);
}
//最后一次性添加到document中
document.body.appendChild(oFragmeng);

(2)先将元素从document中删除,完成修改后再把元素放回原来的位置

(3)将元素的display设置为”none”,完成修改后再把display修改为原来的值

(4)集中修改样式

4.1尽可能少的修改元素style上的属性
  4.2尽量通过修改className来修改样式
  4.3通过cssText属性来设置样式值
    element.style.width=”80px”; //reflow
    element.style.height=”90px”; //reflow
    element.style.border=”solid 1px red”; //reflow
    以上就产生多次reflow,调用的越多产生就越多
    element.style.cssText=”width:80px;height:80px;border:solid 1px red;”; //reflow 
  4.4缓存经常访问的属性
    // 这样很不好
for(big; loop; here) {
el.style.left = el.offsetLeft + 10 + "px";
el.style.top = el.offsetTop + 10 + "px";
}

// 这样会更好
var left = el.offsetLeft,
top = el.offsetTop
esty = el.style;
for(big; loop; here) {
left += 10;
top += 10;
esty.left = left + "px";
esty.top = top + "px";
}
多次使用left,top也就产生一次reflow
  4.5设置元素的position为absolute或fixed
    元素脱离标准流,也从DOM树结构中脱离出来,在需要reflow时只需要reflow自身与下级元素
  4.6尽量不要用table布局
table元素一旦触发reflow就会导致table里所有的其它元素reflow。在适合用table的场合,
可以设置table-layout为auto或fixed,这样可以让table一行一行的渲染,
这种做法也是为了限制reflow的影响范围
  4.7避免使用expression,他会每次调用都会重新计算一遍(包括加载页面)






















































以上是关于根据浏览器渲染引擎工作原理(reflow/repaint),来优化DOM的操作的主要内容,如果未能解决你的问题,请参考以下文章

JS工作原理

画了20张图,详解浏览器渲染引擎工作原理

浏览器的渲染原理

How Javascript works (Javascript工作原理) 渲染引擎及性能优化小技巧

前端必读:浏览器内部工作原理

JS进阶 - 浏览器工作原理