1.页面的渲染过程
(1)Javascript:通过JS实现动画效果或者操作DOM实现交互
(2)Style:计算样式,如果样式有改变将重新计算,并返回给DOM
(3)Layout:根据DOM的样式,重新布局(重排)
(4)Paint:在多个渲染层上,对新的布局重新渲染(重绘)
(5)Composite:将绘制好的多个渲染层合并,显示到页面上
在页面生成时,至少进行一次布局和渲染,在后面用户不断地操作过程中会进行多次的重排和重绘,以至于影响页面的性能。
2.通过JS操作DOM影响页面性能的问题有
(1)访问和修改DOM
(2)修改DOM元素的样式,导致重绘或者重排
(3)通过对DOM元素的事件处理,完成与用户的交互功能
3.DOM操作对页面性能的影响
(1)DOM的修改会导致重排和重绘
重排是指元素的位置或者大小发生了改变,浏览器需要重新去计算渲染树,新的渲染树建立之后,浏览器会重新绘制所影响的元素
重绘是指元素的样式发生了变化,而大小和尺寸没有发生改变
(2)导致页面重排的一些操作
内容改变:文本改变或者图片的尺寸改变
DOM元素的几何属性改变:元素的宽高改变时,原来渲染树中的DOM节点会失效,浏览器会根据DOM的变化重新构建渲染树中的相关节点。如果父元素的几何属性发生变化时,会导致子元素以及兄弟元素的位置发生变化,从而引起重排。
DOM树结构发生变化:添加DOM节点,修改DOM节点的位置以及删除某个节点都会对渲染树进行修改,从而导致重排。浏览器的布局是自上而下的,修改当前元素不会都之前的元素造成影响,但是会对之后的元素造成影响,导致重排。
获取某些属性时:当获取一些属性值时,浏览器为了保证获取到正确的值也会引起重排。如元素的offsetTop,offsetLeft,offsetHeight,offsetWidth,scrollTop,scrollWidth,scrollLeft,scrollHeight、
浏览器窗口尺寸发生改变时:浏览器窗口的尺寸发生改变时,会导致所有元素的尺寸发生变化,从而导致重排。
(3)导致页面重绘的一些操作
只修改元素的样式,而未修改元素的大小和位置,引起重绘
重排一定引起重绘,而重绘不一定引起重排
4.性能优化
(1)浏览器本身的优化策略
浏览器会维护一个队列,将所有引起重排和重绘的操作都放在这个队列里,当操作达到一定的数量或者时间间隔时,浏览器会进行一个批处理。这样可以让多次的重排重绘,变成一次。但是有时候一些特殊的style属性会使这种优化失效,例如offsetTop,scrollTop,clientTop等属性,这些属性都是要实时返回给用户的几何属性或者布局属性,因此浏览器需要立即执行,触发重排返回正确的值。
(2)最小化的重排和重绘
减少对渲染树的操作,并减少对一些style信息的请求。
将多次样式改变属性合并成一次操作(仅适用于单个节点)
//javascript var el = document.getElementById("el"); el.style.color = "red"; el.style.height = "100px"; el.style.width = "20px";
可以使用内联样式的cssText实现
var el = document.getElementById("el"); el.style.cssText = 'color: red; height:100px; width:20px'
还可以使用切换类名的方法
//CSS .active{ color: red; width: 20px; height: 100px; } //javascript var el = document.getElementById("el"); el.className = "active";
批量修改DOM
核心思想:
让元素脱离文本流;对其进行多重改变;将元素带回文档中;
a. 采用display属性隐藏元素,修改之后再显示元素,这样只在显示和隐藏元素是触发两次重排; 将多次需要重排元素,position属性设置为absolute和fixed这样就脱离文档流,元素的变化将不会影响其他元素。使用动画效果的元素最好设置成绝对定位。
b. 使用文档片段创建一个子树,然后再拷贝到文档中。例如要一步获取一个列表中的元素,可以在内存中生成一个列表的HTML片段,然后再一次添加到文档中,而不是每循环一次添加一项。这样就只触发了一次重排。
c. 将原始元素拷贝到一个独立节点中去,然后操作这个独立的节点,覆盖原始元素。
缓存布局信息
当访问offsetTop这种属性时,会冲破浏览器本身的优化,所以应减少对布局信息的查询。可以将属性值赋值给局部变量来参与运算。
var a = el.offsetWidth; a.style.width = 1 + ++a +'px';