之前看到说操作DOM很慢,要尽量少的去操作DOM。当时没有细究,以致于有时候写js还是会纠结,是直接操作DOM还是处理数据后refresh好一点。今天看到一篇文章,虽然还没能完全消化但也是学到不少,顺带着还get了Dev tools下的timeline的正确使用方式,在这里稍微整理一下:
一张页面是如何呈现出来的
简单来说,就是:
- 解析
HTML,生成一棵DOM tree - 解析
css样式,结合DOM tree生成一棵Render tree。render tree与DOM tree并不完全对应,一个简单的例子就是display:none的元素虽然存在于DOM tree中,但是因为不需要被绘制所以不会出现在render tree上。 - 对
Render tree的各个节点计算布局信息,比如box的位置与尺寸。 - 利用浏览器的UI层对
Render tree进行绘制。
在明确了页面的呈现过程后,有个问题就呼之欲出了,那就是:
什么因素会影响页面的渲染速度
事实上,paint就是一个耗时的过程,而第三点中的layout是一个更为耗时的过程。layout发生在页面渲染前,用来计算文档中DOM元素的位置和大小。第一次加载了html文档后就会进行layout操作,之后的js执行和css样式的改变也会触发浏览器去执行layout。甚至一次layout会牵涉到整个文档布局的重新计算。但是layout又无法避免,所以我们需要尽量少的去让游览器做layout。
一般情况下,浏览器的layout是lazy的,也就是说:在js脚本执行时,是不会去更新DOM的,任何对DOM的修改都会被暂存在一个队列中,在当前js的执行上下文完成执行后,会根据这个队列中的修改进行一次layout。然而有时候我们希望在js代码中立刻获取最新的DOM节点信息,这种情况下浏览器就不得不提前执行layout,这是导致DOM性能问题的主因。
一般来说,如下的操作会触发浏览器执行layout:
- 通过
js获取需要计算的DOM属性 - 添加或删除
DOM元素 resize浏览器窗口大小- 改变字体
css伪类的激活,比如:hover- 通过
js修改DOM元素样式且该样式涉及到尺寸的改变