2012-05-03 13 views
55

La gente qui spesso suggeriscono di memorizzare nella cache l'oggetto jQuery creato da un elemento DOM, come con questo codice:

$('#container input').each(function() { 
    $(this).addClass('fooClass'); 
    $(this).attr('data-bar', "bar"); 
    $(this).css('background-color', 'red'); 
}); 
  • Vuol la memorizzazione nella cache l'oggetto jQuery davvero migliorare le prestazioni del nostro codice?
  • Cosa succede "dietro le quinte" quando si passa un elemento DOM al costruttore jQuery?
+16

'$ (questo)' ovviamente significa "' (questo) 'dollari". – BoltClock

+0

Si dovrebbe sempre memorizzare nella cache, ma in questo esempio specifico, non è nemmeno necessario eseguirlo. Approfittate del concatenamento jQuery: '$ (this) .addClass ('fooClass'). Attr ('data bar', 'bar'). Css ('background-color', 'red');' –

risposta

51

In jQuery tag info appare questo avvertimento:

La funzione di jQuery $() è costoso. Chiamarlo ripetutamente è estremamente inefficiente.

Beh ... questo è vero solo per selettori di stringa, che vengono analizzati con espressioni regolari per scoprire quello che sono:

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

Poi se la stringa è un selettore (diverso da id), jQuery attraversa il DOM per trovare una corrispondenza con la sua funzione di costosi find:

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

Quindi sì, è costoso, ma che è vero solo per i selettori!

Se passiamo un DOMElement, l'unica azione jQuery fa è salvare il parametro DOMElement come il contesto dell'oggetto jQuery appena creato e impostare la lunghezza del contesto a 1:

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

ho fatto some tests with jsPerf , e ho trovato che in effetti la memorizzazione nella cache l'oggetto jQuery ha solo un piccolo effetto:

Bar chart, described below

In Chrome è più lento solo il 7%. (In IE è un po 'più significativo: il 12%.)

+24

Nota: La risposta alle tue domande è esplicitamente * incoraggiata. * È perfettamente corretto pubblicare una domanda a cui già conosci la risposta se non è già presente nel sito. Ciò non incoraggia in alcun modo a ri-porre domande popolari. I duplicati saranno chiusi e cancellati. –

+0

In entrambi i casi si salva almeno una chiamata alla volta. – Christoph

+0

Il confronto non è giusto ... C'è una grande differenza nelle prestazioni. –

14

Per rispondere alla tua seconda domanda, guardare il source:

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

Ecco una piccola e graziosa app per visualizzare la fonte: http://james.padolsey.com/jquery/#v=git&fn=jQuery.fn.init – Joe

+3

Ora un selettore di stringhe avrà ovviamente un grafico molto diverso. – Joe

+0

@JoeTuskan. Ho elaborato il tuo commento nella mia risposta aggiornata. – gdoron

10

Per quanto riguarda la differenza di prestazioni, se siete alla ricerca di un Confronto diretto tra i due, è utile rimuovere qualsiasi codice aggiuntivo che potrebbe distorcere il risultato, come la selezione DOM e altri metodi che non sono direttamente correlati.

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

enter image description here

In un ambiente mondo più reale, la relativa differenza è minore, come il test ha mostrato

Un'altra cosa da tenere a mente è che ogni volta che si crea un oggetto jQuery, la memoria deve essere allocata per questo, che si aggiunge al lavoro che il garbage collector deve fare.

Quindi penso che la ragione per cui la gente suggerisce il caching derivi da un punto di vista di principio. Si sta facendo del lavoro supplementare che, sebbene di solito non avrà un impatto notevole, in definitiva richiede un sovraccarico che può essere facilmente evitato.

+0

Buona spiegazione !!! +1 – Gaurav123

+0

Questo confronto è molto meglio del confronto della risposta accettata. –

8

Una cosa che tutti i test di performance di runtime qui manca è un'altra considerazione importante:

larghezza di banda di rete.

Caching $(this) in una variabile locale sarà generalmente diminuire la dimensione dello script, in particolare quando ridotte di (perché this non può essere ridotto da quattro caratteri).

considerare: uscita minified

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

Chiusura del compilatore è

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

Ciò consente di risparmiare 39 byte (20%). Consideriamo:

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

L'uscita minified è

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

Questo risparmia 74 byte (37%), quasi raddoppiando nostri risparmi byte. Ovviamente, i risparmi del mondo reale in script di grandi dimensioni saranno inferiori, ma è comunque possibile ottenere riduzioni significative delle dimensioni dello script tramite la memorizzazione nella cache.

Davvero, c'è solo un lato positivo per la memorizzazione nella cache $(this). Ottieni guadagni prestazionali minuziosi ma misurabili. Ancora più importante, è possibile ridurre il numero di byte che viaggiano sul filo, e che si traduce direttamente in più dollari perché faster page loads equal more sales.

Quando si guarda in questo modo, si potrebbe effettivamente dire che c'è una quantificabile dollaro costare a ripetere $(this) e non caching esso.

+0

+1, Anche se è più una risposta al perché dovresti mettere in cache 'this' not' $ (this) 'perché puoi ottenere lo stesso risultato con' this.value; this.tagName; this.className; this.nodeType; Questo....' – gdoron

+0

@gdoron, c'è una grande differenza tra l'uso di metodi raw DOM e jQuery; non sono sempre intercambiabili. ('addClass',' data', animation ...) A parte questo, c'è ancora una differenza di 3 byte per chiamata tra 'var a = $ (this); un...; a ...; 'e' var a = questo; $ (A) ...; $ (a) ...; ' – josh3736

+0

Se stai facendo un gzipping dei tuoi file, troverai spesso che le dimensioni del file sono un po 'più grandi a causa di tale memorizzazione nella cache. Nel tuo esempio, è solo una piccola differenza di byte, 111 vs 115 byte, ma sottolinea il punto. Non ho idea del perché sia ​​così, ma ho spesso trovato questo il caso. –

Problemi correlati