當dom 改變影響到元素的幾何屬性(寬和高)——例如改變了邊框寬度或在段落中新增文字,將發生一系列後續動作——瀏覽器需要重新計算元素的幾何屬性,而且其他元素的幾何屬性和位置也會因此改變受到影響。瀏覽器使渲染樹上受到影響的部分失效,然後重構渲染樹。這個過程被稱作重排版。重排版完成時,瀏覽器在乙個重繪程序中重新繪製螢幕上受影響的部分。
不是所有的dom 改變都會影響幾何屬性。例如,改變乙個元素的背景顏色不會影響它的寬度或高度。在這種情況下,只需要重繪(不需要重排版),因為元素的布局沒有改變。
重繪和重排版是負擔很重的操作,可能導致網頁應用的使用者介面失去相應。所以,十分有必要盡可能減少這類事情的發生。
1)考慮下面這個例子,它改變同乙個風格屬性三次(這也許不是你在真正的**中所見到的,不過它孤立地展示出乙個重要話題):
// setting and retrieving styles in successionvar computed,
tmp = '',
bodystyle = document.body.style;
if (document.body.currentstyle) else
// inefficient way of modifying the same property
// and retrieving style information right after
bodystyle.color = 'red';
tmp = computed.backgroundcolor;
bodystyle.color = 'white';
tmp = computed.backgroundimage;
bodystyle.color = 'green';
tmp = computed.backgroundattachment;
在這個例子中,body 元素的前景色被改變了三次,每次改變之後,都匯入computed 的風格。匯入的屬性backgroundcolor, backgroundimage, 和backgroundattachment 與顏色改變無關。然而,瀏覽器需要重新整理渲染佇列並重排版,因為computed 的風格被查詢而引發。
比這個不講效率的例子更好的方法是不要在布局資訊改變時查詢它。如果將查詢computed 風格的**搬到末尾,**看起來將是這個樣子:
bodystyle.color = 'red';bodystyle.color = 'white';
bodystyle.color = 'green';
tmp = computed.backgroundcolor;
tmp = computed.backgroundimage;
tmp = computed.backgroundattachment;
在所有瀏覽器上,第二個例子將更快,重排版和重繪代價昂貴,所以,提高程式響應速度乙個好策略是減少此類操作發生的機會。為減少發生次數,你應該將多個dom 和風格改變合併到乙個批次中一次性執行。
2)考慮這個例子:
var el = document.getelementbyid('mydiv');el.style.borderleft = '1px';
el.style.borderright = '2px';
el.style.padding = '5px';
這裡改變了三個風格屬性,每次改變都影響到元素的幾何屬性。在這個糟糕的例子中,它導致瀏覽器重排版了三次。大多數現代瀏覽器優化了這種情況只進行一次重排版,但是在老式瀏覽器中,或者同時有乙個分離的同步程序(例如使用了乙個定時器),效率將十分低下。如果其他**在這段**執行時查詢布局資訊,將導致三次重布局發生。而且,此**訪問dom 四次,可以被優化。
乙個達到同樣效果而效率更高的方法是:將所有改變合併在一起執行,只修改dom 一次。可通過使用
csstext 屬性實現:
var el = document.getelementbyid('mydiv');
el.style.csstext = 'border-left: 1px; border-right: 2px; padding: 5px;';
這個例子中的**修改csstext 屬性,覆蓋已存在的風格資訊。如果你打算保持當前的風格,你可以將它附加在csstext 字串的後面。
el.style.csstext += '; border-left: 1px;';
另乙個一次性改變風格的辦法是修改css 的類名稱,而不是修改內聯風格**。這種方法適用於那些風格不依賴於執行邏輯,不需要計算的情況。改變css 類名稱更清晰,更易於維護;它有助於保持指令碼免除顯示**,雖然它可能帶來輕微的效能衝擊,因為改變類時需要檢查級聯表。
var el = document.getelementbyid('mydiv');
el.classname = 'active';
當你需要對dom 元素進行多次修改時,你可以通過以下步驟減少重繪和重排版的次數:
1.從文件流中摘除該元素
2.對其應用多重改變
3.將元素帶回文件中
此過程引發兩次重排版——第一步引發一次,第三步引發一次。如果你忽略了這兩個步驟,那麼第二步
中每次改變都將引發一次重排版。
有三種基本方法可以將dom 從文件中摘除:
1) 隱藏元素,進行修改,然後再顯示它。
2) 使用乙個文件片斷在已存dom 之外建立乙個子樹,然後將它拷貝到文件中。
3) 將原始元素拷貝到乙個脫離文件的節點中,修改副本,然後覆蓋原始元素。
為演示脫離文件操作,考慮這樣乙個鏈結列表,它必須被更多的資訊所更新:
假設附加資料已經儲存在乙個物件中了,需要插入到這個列表中。這些資料定義如下:
var data = [,];
下面是乙個通用的函式,用於將新資料更新到指定節點中:
var a, li;
for (var i = 0, max = data.length; i < max; i++)
};如前面所討論過的,減少重排版的乙個方法是通過改變display 屬性,臨時從文件上移除元素然後再恢復它。
var ul = document.getelementbyid('mylist');ul.style.display = 'none';
ul.style.display = 'block';
另一種減少重排版次數的方法是:在文件之外建立並更新乙個文件片斷,然後將它附加在原始列表上。文件片斷是乙個輕量級的document 物件,它被設計專用於更新、移動節點之類的任務。文件片斷乙個便利的語法特性是當你向節點附加乙個片斷時,實際新增的是文件片斷的子節點群,而不是片斷自己。下面的例子減少一行**,只引發一次重排版,只觸發「存在dom」一次。
var fragment = document.createdocumentfragment();第三種解決方法首先建立要更新節點的副本,然後在副本上操作,最後用新節點覆蓋老節點:
var old = document.getelementbyid('mylist');
var clone = old.clonenode(true);
old.parentnode.replacechild(clone, old);
推薦盡可能使用文件片斷(第二種解決方案)因為它涉及最少數量的dom 操作和重排版。唯一潛在的缺點是,當前文件片斷還沒有得到充分利用,開發者可能不熟悉此技術。
瀏覽器通過佇列化修改和批量執行的方法,儘量減少重排版次數。當你查詢布局資訊如偏移量、滾動條位置,或風格屬性時,瀏覽器刷佇列並執行所有修改操作,以返回最新的數值。最好是儘量減少對布局資訊的查詢次數,查詢時將它賦給區域性變數,並用區域性變數參與計算。
考慮乙個例子,將元素myelement 向右下方向平移,每次乙個畫素,起始於100×100 位置,結束於500×500位置,在timeout 迴圈體中你可以使用:
// inefficientmyelement.style.left = 1 + myelement.offsetleft + 'px';
myelement.style.top = 1 + myelement.offsettop + 'px';
if (myelement.offsetleft >= 500)
這樣做很沒效率,因為每次元素移動,**查詢偏移量,導致瀏覽器重新整理渲染佇列,並沒有從優化中獲益。另乙個辦法只需要獲得起始位置值一次,將它存入區域性變數中var current = myelement.offsetleft;。然後,在動畫迴圈中,使用current 變數而不再查詢偏移量:
current++myelement.style.left = current + 'px';
myelement.style.top = current + 'px';
if (current >= 500)
效能優化 頁面渲染 重繪 回流
參考 高效能web開發 深入理解頁面呈現 重繪 回流 因為一些原因要重新構建渲染數的時候,就叫做回流,第一次構建的時候也叫做回流。引起回流的操作 回流一定會導致重繪 影響元素幾何屬性發生變化 重繪 瀏覽器會使渲染樹中受到影響的部分失效,並重新構造這部分渲染樹,完成回流後,瀏覽器會重新繪製受影響的部分...
頁面回流和重繪的優化
在頁面中 js的執行和css的執行其實是兩條執行緒 我們只知道 最終的rendertree是由 domtree cssomtree js 的作用下 來生成的 但是js 的執行最終要依賴 domtree cssomtree的生成結果,這樣就導致了 css的執行 阻塞了js的執行,因此,我們把css 的...
頁面重繪 repaint 和回流 reflow
前言 頁面顯示到瀏覽器上的過程 1.1 生成乙個dom樹。瀏覽器將獲取到的html 解析成1個dom樹,包含了所有標籤,包括display none和動態新增的節點。1.2 生成樣式結構體。瀏覽器將所有樣式解析成樣式結構體,解析過程中會去掉瀏覽器不能識別的。2 dom樹和樣式結構體結合生成rende...