2012-05-03 39 views
55

這裏的人們常提示緩存從DOM元素創建jQuery對象,像這樣的代碼:

$('#container input').each(function() { 
    $(this).addClass('fooClass'); 
    $(this).attr('data-bar', "bar"); 
    $(this).css('background-color', 'red'); 
}); 
  • 是否緩存jQuery對象真正改善我們的代碼的性能?
  • 當您將DOM元素傳遞給jQuery構造函數時,「幕後」會發生什麼?
+16

'$(this)'明顯的意思是「'(this)'dollars」。 – BoltClock

+0

你應該總是緩存,但在這個特定的例子中,你甚至不需要這樣做。只需利用jQuery鏈接:'$(this).addClass('fooClass')。attr('data-bar',「bar」).css('background-color','red');' –

回答

51

在jQuery的tag info出現這樣的警告:

jQuery函數$()是昂貴的。多次調用它是非常低效的。

嗯......只有字符串選擇,其中獲得與正則表達式解析,找出它們是什麼是正確的:

quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/ 

這時如果字符串是一個選擇器(比其他id) jQuery的遍歷DOM找到匹配其昂貴find功能:

} else if (!context || context.jquery) { 
    return (context || rootjQuery).find(selector); 
} 

所以是它的價格昂貴,但僅適用於選擇真!

如果我們傳遞一個DOMElement,唯一的動作jQuery不會是保存一個DOMElement參數爲新創建的jQuery對象的上下文和語境的長度設置爲1:

// Handle $(DOMElement) 
if (selector.nodeType) { 
    this.context = this[0] = selector; // Selector here is a DOMElement 
    this.length = 1; 
    return this; 
} 

我做some tests with jsPerf ,我發現確實緩存jQuery對象只有一點點效果:

Bar chart, described below

在Chrome中是慢了7%。 (在IE中它是一點點顯著:12%)。

+24

注意:明確地*鼓勵回答你自己的問題。*如果問題已經出現在網站上,你可以發佈你已經知道答案的問題。這絕不鼓勵重新提出熱門問題。重複將被關閉並刪除。 –

+0

無論哪種情況,您每次至少保存一個函數調用。 – Christoph

+0

比較不正確......性能有很大差異。 –

14

要回答你的第二個問題,看看source

// Handle $(DOMElement) 
if (selector.nodeType) { 
    this.context = this[0] = selector; 
    this.length = 1; 
    return this; 
} 
+1

這是一個不錯的小應用程序來查看源代碼:http://james.padolsey.com/jquery/#v=git&fn=jQuery.fn.init – Joe

+3

現在,字符串選擇器顯然會有一個非常不同的圖形。 – Joe

+0

@JoeTuskan。我在更新後的答案中闡述了你的評論。 – gdoron

10

對於性能上的差異,如果你正在尋找一個直接比較兩者之間的差異,可以刪除任何可能導致結果偏斜的額外代碼,如DOM選擇和其他不直接相關的方法。

http://jsperf.com/this-cost/2

enter image description here

在一個更真實的世界設定,相對差異是次要的測試表明

另一件事要記住的是,每次你創建一個jQuery對象,內存需要分配給它,這增加了垃圾回收器需要做的工作。

所以我認爲人們建議高速緩存的原因是從某種原則性的角度出發的。額外的工作正在完成,雖然通常不會有明顯的影響,但最終還是需要一些可以輕鬆避免的開銷。

+0

很好的解釋! +1 – Gaurav123

+0

這個比較比接受答案的比較要好得多。 –

8

一兩件事,所有這裏的運行時性能測試懷念的是另一個重要的考慮因素:

網絡帶寬。

緩存$(this)到一個局部變量通常會降低你的腳本的大小,精縮尤其是當(因爲this不能從四個字符減少)。

考慮:

function hello(text) { 
    $(this).attr(); 
    $(this).css(); 
    $(this).data(); 
    $(this).click(); 
    $(this).mouseover(); 
    $(this).mouseleave(); 
    $(this).html(text); 
} 
hello('Hello world'); 

Closure編譯器的縮小的輸出是

function hello(a){$(this).attr();$(this).css();$(this).data();$(this).click();$(this).mouseover();$(this).mouseleave();$(this).html(a)}hello("Hello world"); 

這樣可以節省39個字節(20%)。現在考慮:

function hello(name) { 
    var $this = $(this); 
    $this.attr(); 
    $this.css(); 
    $this.data(); 
    $this.click(); 
    $this.mouseover(); 
    $this.mouseleave(); 
    $this.html(name); 
} 
hello('Hello world'); 

縮小的輸出是

function hello(b){var a=$(this);a.attr();a.css();a.data();a.click();a.mouseover();a.mouseleave();a.html(b)}hello("Hello world"); 

這樣可以節省74個字節(37%),幾乎翻了一番我們節省字節。顯然,在大型腳本中真實世界的節省將會降低,但是仍然堅持通過緩存來顯着減少腳本的大小。

真的,高速緩存$(this)只有一個好處。您可以獲得微乎其微但可衡量的運行時性能增益。更重要的是,您可以減少通過線路傳輸的字節數,並且直接轉換爲更多美元,因爲faster page loads equal more sales

當你看到這樣的說法,你實際上可以說有一個量化的美元成本來重複$(this),而不是將其高速緩存。

+0

+1,儘管它更多的是回答你爲什麼要緩存'this'而不是'$(this)',因爲你可以用this.value得到相同的結果。 this.tagName; this.className; this.nodeType;這個....' – gdoron

+0

@gdoron,使用原始DOM和jQuery方法有很大區別;它們並不總是可以互換的。 ('addClass','data',animation ...)除此之外,'var a = $(this)之間的每次調用仍然有3字節的差異。一個...; a ...;'和'var a = this; $(一)...; $(a)...;' – josh3736

+0

如果你正在瀏覽你的文件,你會經常發現由於這種緩存的緣故,文件大小有點大。在你的例子中,它只有幾個字節的差別,111對115個字節,但它強調了這一點。我不知道這是爲什麼,但我經常發現這是事實。 –

相關問題