2012-11-02 122 views
9

我知道做多個dom操作是不好的,因爲它會強制多次重繪。「虛擬」dom操縱?

即:

$('body').append('<div />') 
     .append('<div />') 
     .append('<div />') 
     .append('<div />'); 

取而代之的是更好的做法顯然是:

$('body').append('<div><div></div><div></div><div></div><div></div></div>'); 

但我好奇的虛擬操作

即:

$('<div />').append('<div />') 
      .append('<div />') 
      .append('<div />') 
      .append('<div />') 
      .appendTo('body'); 

是仍然不好,很明顯,調用一個函數會有一些開銷,但是會有什麼嚴重的性能命中?


原因,我問的是這樣的:

var divs = [ 
    {text: 'First', id: 'div_1', style: 'background-color: #f00;'}, 
    {text: 'Second', id: 'div_2', style: 'background-color: #0f0;'}, 
    {text: 'Third', id: 'div_3', style: 'background-color: #00f;'}, 
    {text: 'Fourth', id: 'div_4', style: 'background-color: #f00;'}, 
    {text: 'Fifth', id: 'div_5', style: 'background-color: #0f0;'}, 
    {text: 'Sixth', id: 'div_6', style: 'background-color: #00f;'} 
]; 

var element = $('<div />'); 

$.each(divs, function(i,o){ 
    element.append($('<div />', o)); 
}); 

$('body').append(element); 

想像一下div的陣列已經從描述形式的數據庫表(好吧,我使用的div的例子,但也可以是很容易取代輸入)或類似的東西。

或「推薦」的版本中,我們有:

var divs = [ 
    {text: 'First', id: 'div_1', style: 'background-color: #f00;'}, 
    {text: 'Second', id: 'div_2', style: 'background-color: #0f0;'}, 
    {text: 'Third', id: 'div_3', style: 'background-color: #00f;'}, 
    {text: 'Fourth', id: 'div_4', style: 'background-color: #f00;'}, 
    {text: 'Fifth', id: 'div_5', style: 'background-color: #0f0;'}, 
    {text: 'Sixth', id: 'div_6', style: 'background-color: #00f;'} 
]; 

var element = '<div>'; 

$.each(divs, function(i,o){ 
    element += '<div '; 

    $.each(o, function(k,v){ 
     if(k != 'text'){ 
      element += k+'="'+v+'" '; 
     }    
    }); 

    element += '>'+o.text+'</div>'; 

}); 

element += '</div>'; 

$('body').append(element); 
+0

@nathan草場:「好像它仍然很糟糕」 ---爲何如此? 「爲什麼不使用」---爲什麼不把它保持原樣呢? – zerkms

+0

@nathan hayfield:「快得多」?你可以告訴** REAL **區別5個「附加」調用vs連接嗎?該代碼是爲人們編寫的,它只是優化**它不符合性能要求。 – zerkms

+2

重繪可能會推遲到您處理的事件完成之後。 – millimoose

回答

9

首先,雖然它是偉大的,瞭解潛在的性能命中這樣你應該總是通過測量來看看你甚至有一個問題開始。

如果你無法感知的問題,寫最可讀的代碼。

如果你能感覺到一個問題,措施,改變和措施。

說了這麼多之後,您發佈的最後一個示例涉及到尚未寫入DOM的元素,因此直到appendTo將元素添加到DOM時纔會重新繪製。

我會感到非常驚訝,如果你能抓住第二個和第三個例子之間的速度差 - 而且相當驚訝,如果你能看到的任何人之間的主要區別。

+0

但是,將文檔片段方法用作最佳做法(如果可能的話) –

+0

只要它不會損害可讀性就沒有問題。瀏覽器廠商都在努力讓他們的瀏覽器速度超快,所以你只需要擔心讓代碼易於理解和改變。 – Fenton

+0

我不確定你寫的應用有多大。但是我一直在編寫企業級應用程序,這些應用程序是時間性能很好的應用程序,儘管我很早就厭倦了不成熟的優化,但我們選擇採用一些已知速度更快的做法......我不'地愛它,但我討厭的應用程序在IE瀏覽器正在緩慢甚至更 –

1

如果追加節點時,真的很擔心性能,你需要使用documentfragments。這些將允許您在不重繪的情況下將元素附加到dom。 John Resign在這個主題上有一個excellent article。他注意到性能提高了200-300%。我在我的一個應用程序中實現了文檔片段,並可以確認他的聲明。

+1

jQuery已經在內部使用文檔片段,當你做'$「(」

「)' –

+0

@Juan:嗯 - 是的。感謝您指出(抱歉,我來自香草背景)。 –

+0

需要注意的是這篇文章是在4年前寫的。在Chrome開發者工具中記錄時間線告訴我他的測試頁面只執行一次佈局和繪畫。 – millimoose

1

不管發生在良好的老一代的標記在運行時? 嚴重的是,發生了什麼?

我同意@ Sohnee關於可讀性重要性的觀點,但DOM操作是瀏覽器可以執行的一些最昂貴的操作。維護一串標記的選項可以做到完全可讀,並且提供超出可以忽略的用戶體驗改進。

this jsperf中,我們在運行時創建了一個10x100表格 - 這對於數據分頁是一個完全合理的(而不是迄今爲止最複雜的情​​景)。在運行最新版本Chrome的四核機器上,直接DOM操作腳本需要60ms才能完成,而標記緩存需要3ms。

這是在我的設置上難以區分的差異,但那些坐在企業防火牆後面仍然被迫使用過時版本的IE瀏覽器的糟糕數字處理人員呢?如果所需的DOM操作會變得更加沉重,屬性操作和積極強迫?

我只是說如果你想優化一些JavaScript,這不是一個糟糕的地方開始。

+0

AJAX發生了;)如果你關心可憐的IE用戶,那麼你也可以提供一個無AJAX的版本,但通常JavaScript標記生成提供了一個更友好的界面,例如,可以說你有一個'添加另外10個屬性按鈕,顯示10個以上的輸入,確保您可以生成500個輸入以開始顯示/隱藏,或者,您可以即時生成10個,如果在運行時有意義生成標記,但它有真正的用例。 – Hailwood

+0

@Hailwood:ಠ_ಠ*當然* ajax發生了!當我在運行時討論標記生成時,我認爲它很明顯是建議在客戶端上* - 即先將json數據轉換爲html字符串,然後將其添加到DOM –

+0

那麼在那種情況下它確實只是一個可讀性的例子,並且jQuery讓我們懶惰,讓jQuery處理它比自己做起來更容易,但是在可讀性和'運行時標記生成'這點上,這正是最後一個例子在我的問題中,但看看上面的例子,你會如何讓它們同樣可讀? – Hailwood