前端頁面卡頓-代碼優化


  原文地址--->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元素上綁定事件或影響頁面的性能,一方面,綁定事件本身會占用處理時間,另一方面,瀏覽器保存事件綁定也會占用內存。使用事件托管方式,即利用事件冒泡機制,只在父元素上綁定事件處理,用於處理所有子元素的事件,在事件處理函數中根據傳入的參數判斷事件源元素,針對不同的元素做不同的處理。這種方式有很大的靈活性,可以方便的添加或刪除子元素,不需要考慮因元素移除或添加需要修改事件綁定。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM