2009-12-04 32 views
6

有人能證明給我的建議是here(複製如下)關於刪除dom元素之前修改它們,然後重新插入它們更快。Javascript性能 - Dom Reflow - Google文章

通過證明,我想看到一些數字。他們非常喜歡研究這個,但是我認爲這篇文章非常薄弱,沒有具體說明'問題'究竟是什麼以及解決方案如何解決速度問題(文章標題爲加速JavaScript)

文章....

亂的流DOM操作

這種模式讓我們創建多個元素,並將它們插入到DOM觸發單迴流。它使用了一種叫做DocumentFragment的東西。我們在DOM之外創建一個DocumentFragment(所以它是不流動的)。然後,我們爲此創建並添加多個元素。最後,我們將DocumentFragment中的所有元素移動到DOM,但觸發一次迴流。 問題

讓我們來創建一個函數,它改變一個元素中所有錨點的className屬性。我們可以通過迭代每個錨點並更新它們的href屬性來完成此操作。問題是,這可能導致每個錨的迴流。

function updateAllAnchors(element, anchorClass) { 
    var anchors = element.getElementsByTagName('a'); 
    for (var i = 0, length = anchors.length; i < length; i ++) { 
    anchors[i].className = anchorClass; 
    } 
} 

解決方案

爲了解決這個問題,我們可以從DOM刪除元素,更新所有錨,然後插入元素回原處。爲了實現這一點,我們可以編寫一個可重用的函數,它不僅從DOM中移除一個元素,而且還返回一個函數,將該元素插回原始位置。

/** 
* Remove an element and provide a function that inserts it into its original position 
* @param element {Element} The element to be temporarily removed 
* @return {Function} A function that inserts the element into its original position 
**/ 
function removeToInsertLater(element) { 
    var parentNode = element.parentNode; 
    var nextSibling = element.nextSibling; 
    parentNode.removeChild(element); 
    return function() { 
    if (nextSibling) { 
     parentNode.insertBefore(element, nextSibling); 
    } else { 
     parentNode.appendChild(element); 
    } 
    }; 
} 

現在我們可以使用此功能即出即用的流單元內更新的錨,只會引發迴流,當我們刪除的元素,當我們插入的元素。

function updateAllAnchors(element, anchorClass) { 
    var insertFunction = removeToInsertLater(element); 
    var anchors = element.getElementsByTagName('a'); 
    for (var i = 0, length = anchors.length; i < length; i ++) { 
    anchors[i].className = anchorClass; 
    } 
    insertFunction(); 
} 

回答

5

你會發現很難從javascript分析得到有意義的數字爲這是你真的對儲蓄重新繪製和重新流動,不會在大多數分析工具出現。您可以使用Firebug paint events extension來直觀地向您顯示您正在保存的重繪次數。

+0

不錯的擴展,但是這兩個例子似乎都爲我做了相同數量的重繪。任何你可以在pastebin.me上進行演示的機會:) – redsquare 2009-12-04 02:39:02

+0

我會承認這個擴展減慢了很多事情,所以有時很難看出計算繁重的操作上的差別,例如, Google地圖縮放。 – Alex 2009-12-04 02:53:28

1

簡短的回答是,的變化而變化,以實際的頁面觸發的DOM JavaScript事件,CSS評價,傳播會影響周圍的DOM的其餘部分的解釋,等通量斷開連接的節點沒有像他們那樣的東西,對他們的操縱便宜得多。

一個比喻:如果你是一個在玩具總動員4上工作的動畫師,而在近乎最終的渲染中,你看到了需要在場景的物理佈局中做出的改變,你會在做全功能時做出修改嗎?細節會重新渲染以檢查場景,或者在進行這些更改時關閉紋理和顏色並降低分辨率?

+0

我想要的數字。好處在哪裏。理論是偉大的。就像伊拉克有WOMD一樣,看看發生了什麼。我仍然沒有看到它是如何使js更快。我已經介紹過它,並沒有看到任何好處。只是想知道我錯過了什麼。 – redsquare 2009-12-04 01:41:01

+0

@redsquare:該文章的標題具有誤導性,在某些方面不準確。它不一定會讓JS更快......它使瀏覽器更快地呈現DOM。換句話說,JS的運行速度可能更快(甚至更慢),但頁面顯示速度會更快,因爲瀏覽器不得不花費更少的時間重新刷新和重新繪製。迴流和重新繪製是瀏覽器呈現HTML和CSS的方式。 JS性能與瀏覽器渲染性能不一樣。舉個例子,即使你的網站沒有JS,表格的渲染也很昂貴。 – Pauan 2010-12-31 01:19:33

+0

@redsquare:我認爲他們稱之爲「加速JavaScript」的原因是因爲JS通常是觸發迴流和重繪的東西。換句話說,通過改變你的JS代碼,你可以讓頁面看起來更快。但它並沒有顯得更快,因爲JS速度更快,它顯得更快,因爲瀏覽器正在迴流並減少重新繪製。例如,操縱DOM的Java小程序可能同樣糟糕,因此將其稱爲「JavaScript速度」是不準確的。這實際上是渲染速度。 – Pauan 2010-12-31 01:21:34

2

我在頁面上放置了一些鏈接,並在文章中測試了該方法,與使用仍在頁面中的元素設置類名相比。我在Firefox 3,IE 8和鉻3.

嘗試這樣我提出的類爲具有不同的顏色和不同的字體大小的鏈接。由於鏈接文本對於不同的類有不同的大小,我確定頁面確實需要重新排版。

對於任何合理數量的鏈接(高達幾千),刪除和添加元素會稍微慢一些。

對於非常大量的鏈接(10000),刪除和添加元素的速度稍快。

但是,差別很小。你必須有幾千個鏈接才能注意到任何差異,而在10000個鏈接上,仍然只有20%的差異。

所以,我發現,你不能指望從這種方法的任何戲劇性的變化。如果您遇到性能問題,可能有其他方法可以提供更好的結果。例如,我會嘗試更改父元素的類名而不是所有子元素,並讓CSS完成工作。我之前做過的測試表明,這個速度可能快十倍。

0

除了查看頁面之外,沒有可靠的方法來確定迴流何時完成。

花費的時間計算對於一次或一個一個地添加或更改元素幾乎是相同的。該腳本不會等待瀏覽器之間的元素,瀏覽器趕上。

有時你想馬上看到一些東西,即使渲染整個東西需要更長的時間 - 其他時候你想等待一會兒,並在準備就緒時顯示它。

如果你不能說哪一個更好,讓設計師去看一個又一個的一次性版本,但不要問兩個設計師!

2

這或多或少與使用documentFragments初始化元素而不是dom相同。文檔片斷最終會變得更快,因爲它們的結構和實際渲染都不需要擔心。

這裏有一些約翰Resig的對文件片斷的性能優勢(這是在使用jQuery中目前)注意事項:

http://ejohn.org/blog/dom-documentfragments/