前端页面卡顿-代码优化

  原文地址--->http://developer.51cto.com/art/201504/473422.htm

  最近做项目时遇到了页面加载卡顿问题,一时没有头绪,感到无从下手,看到这篇文章,所以整体梳理了一下,在此记录。

在富客户端网页应用中,界面上的UI的更改是通过DOM操作实现的。

    尽管DOM提供了丰富接口供外部调用,但是dom操作的代价很高,

页面前端代码的性能瓶颈大多集中在DOM操作上,因此,前端性能优化的

一个主要的关注点是dom操作的优化,因此我们可以想办法通过尽量减少

DOM操作来优化性能。

   首先,DOM操作为什么会影响性能。在浏览器中,DOM的实现和ECMAScript

的实现是分离的。例如,在IE中,ECMAScript的实现在jscript.dll中,而DOM的

实现在mshtml.dll中;在chrome中使用webkit的WebCore处理DOM和渲染,但

ECMAScript是在V8引擎中实现的,其他浏览器的情况类似,所以通过Javascript

调用dom接口,是相当于两个模块的交互。相比较在同一模块中的调用,这种跨模块的

调用其性能损耗是很高的,但DOM操作对性能影响最大是因为它导致了浏览器的重绘

和重排。

浏览器渲染原理的简单说明

从下载文档到渲染页面的过程中,浏览器会通过解析HTML文档来构建DOM树,解析

CSS产生CSS规则树。javascript在代码解析的过程中,可能会修改生成的dom树

和css规则树,之后根据dom树和css规则树构建渲染树,在这个过程中css会根据

选择器匹配HTML元素。渲染树包括了每个元素的大小,边距等样式属性。渲染树

中不包含隐藏元素及head元素等不可见元素。最后浏览器根据元素的坐标和大小

来计算每个元素的位置,并绘制这些元素到页面上。重绘指的是元素的位置或尺寸

发生了改变,浏览器会重新绘制页面上受影响的元素,重排的代价高于重绘。

之下的DOM操作会导致重绘或重排:

  1.增加,删除和修改可见DOM元素

  2. 页面初始化的渲染

  3.移动dom元素

  4.修改css样式,改变dom元素的尺寸

  5.dom元素内容改变,使得尺寸被撑大

  6.浏览器窗口尺寸改变

  7.浏览器窗口滚动

现代浏览器会针对重排或重绘做性能优化,例如,把DOM操作积累一批后统一

做一次重排或重绘,但在有些情况下,浏览器会立即进行重排或重绘,比如请求如下的

dom元素布局信息

offsetTop/Left/Width/Height

scrollTop/Left/Width/Height

clientTop/Left/Width/Height

getComputeStyle()或currentStyle

因为这些值都是动态计算的,所以浏览器需尽快完成页面绘制,计算返回值,打乱了重绘或

重排优化。

可以遵循一些最佳实践来降低影响-->

方法一:合并多此dom操作为单次dom操作

通过class类名来元素的大量样式更改,代码维护性较好。

通过innerHTML接口来修改DOM元素的内容时,以字符串方式拼接好代码后,一次性赋值给

DOM元素的innerHTML接口。

方法二: 把DOM元素离线或隐藏后修改

把元素从页面流中脱离或隐藏,这样处理后,只会在DOM元素脱离或添加时,或者是隐藏或显示时才会造成页面的重绘会重排,对脱离了页面布局的DOM元素操作就不会导致页面的性能问题。

这种方式适合需要大批量修改dom元素的情况。具体方式由三种:

(1) 使用文档片段

文档片段是一个轻量级的document对象,并不会和特定的页面关联,通过在文档片段上进行DOM操作,可以降低DOM操作对页面性能的影响,这种方式是创建一个文档片段,并在此片段上

进行必要的DOM操作,操作完成后将它附加在页面中,对页面的影响只存在于最后把文档片段附加到页面的这一步操作上。

var fragment=document.createDocumentFragment();

//一些基于fragment的大量dom操作

...

document.getElementById('myElement').appendChild(fragment);

(2)隐藏元素

通过隐藏元素,达到在页面上移除元素的效果,经过大量的DOM操作后恢复元素原来的display样式,只有隐藏和显示元素时会引起页面重绘或重排操作。

var myElement=document.getElementById('myElement');
myElement.style.display='none';

//dom操作

myElement.style.display='block';

(3)克隆DOM元素到内存中

把页面上的DOM元素克隆一份到内存中,然后在内存中操作克隆的元素,操作完成后使用此克隆元素替换页面中原来的DOM元素,只有替换元素时会影响性能,在内存中操作克隆元素不会引起页面上的性能损耗。

var old=document.getElementById('myElement');

var clone=old.cloneNode(true);

//dom操作

old.parentNode.replaceChild(clone,old);

3.设置具有动画效果的DOM元素的position属性为fixed或absolute

把页面中具有动画效果的元素设置为绝对定位,使得元素脱离页面布局流,从未避免了页面频繁的重排,只涉及动画元素自身的重排。这种做法可以提高动画效果的展示性能。(在动画开始时将其设置为绝对定位,等动画结束后恢复原始的定位设置)。

4.谨慎获得dom元素的布局信息,变量本地化。

把获取到的元素的布局信息值缓存在局部变量中。在有大量的DOM操作时,避免获取dom元素的布局信息,如果需要布局信息,最好在DOM操作之前就取好存放。

5.使用事件托管方式绑定事件

在DOM元素上绑定事件或影响页面的性能,一方面,绑定事件本身会占用处理时间,另一方面,浏览器保存事件绑定也会占用内存。使用事件托管方式,即利用事件冒泡机制,只在父元素上绑定事件处理,用于处理所有子元素的事件,在事件处理函数中根据传入的参数判断事件源元素,针对不同的元素做不同的处理。这种方式有很大的灵活性,可以方便的添加或删除子元素,不需要考虑因元素移除或添加需要修改事件绑定。

原文地址:https://www.cnblogs.com/jjworld/p/6491799.html