Performance in jQuery

 

L'altro giorno, mentre assieme a Tommaso stavamo controllando un problema di performance su alcuni script JS, per puro sbaglio mi è capitato di vedere usare jQuery con dei selettori usati in maniera che credevo essere impropria, a prima vista mi sembrava un errore, per questo motivo ho fatto alcuni test per vedere se lo era e i risultati sono stati inaspettati.

La selezione di elementi (in javascript, quindi anche in jQuery) è uno dei punti critici prestazionali in uno script, sopratutto quando la struttura del DOM è molto complessa o si hanno pagine molto corpose, per questo motivo solitamente si creano variabili che contengono gli elementi più comuni e si utilizzano ricerche all'interno di questo gruppo. Sempre per questo motivo (ma non solo), quando si creano plugin le ricerche interne vengono fatte all'interno del subset su cui si è istanziato il plugin.

Per capirci, se creiamo un plugin che necessiti di effettuare una ricerca su tutti i link all'interno del menù, solitamente le ricerche al suo interno vengono fatto usando come riferimento per la ricerca l'istanza del plugin, quindi:

$('a', this).each(function () { /* */ });

questo limita la ricerca all'interno della parte selezionata inizialmente quando abbiamo agganciato il plugin, limitando quindi la parte del DOM che deve essere attraversata per raggiungere gli elementi che ci interessano. Fin qui tutto è lineare e abbastanza normale, cosa succede quando invece andiamo a cercare una serie di elementi nella pagina utilizzerei la ricerca facendo:

$('#menu-container a').each(function () { /* */ });

In questo modo viene effettuata la ricerca per gli elementi indicati in tutto il documento. L'utilizzo che ne ho visto fare, invece, è la seguente:

$('a', '#menu-container').each(function () { /* */ });

in questo caso mi sarei aspettato una doppia ricerca (il secondo risultato, non è più un oggetto del DOM, ma una stringa, quindi deve essere cercata nella pagina), una prima per identificare il contenitore principale (il menu-container) e un'altra per la ricerca del tag a dentro il primo risultato della ricerca, quindi mi sarei aspettato un tempo di ricerca degli elementi maggiore nel secondo caso che non nel primo.

Andando ad effettuare dei test facendo una ricerca per un centinaio di volte e usando le funzioni di debug di FireBug, eseguendo il seguente codice:

$(document).ready(function () {
  console.time("select element nested");
  for(var i = 0; i < 100; i++ ) {
    $('#menu-container a');
  };
  console.timeEnd("select element nested");
});

che sarebbe come l'avrei scritto io, e la seconda versione del codice:

$(document).ready(function () {
  console.time("select element single");
  for(var i = 0; i < 100; i++ ) {
    $('a', '#menu-container');
  };
  console.timeEnd("select element single");
});

in cui invece si ha una doppia ricerca, vediamo che i risultati (in tempo) della ricerca sono notevolmente differenti, infatti abbiamo:

  • select element nested: 1270ms
  • select element single: 26ms

il che è a dir poco stupefacente, circa il 4800% in più nella velocità della ricerca, ma ancora più stupefacente è il risultato della ricerca quando non sono presenti risultati (ma questo è già più accettabile), infatti

  • select element nested: 1440ms
  • select element single: 9ms

è ben 16000% più efficace nel "non trovare" il risultato.

Sono dati estratti su alcune pagine su cui ho effettuato il test usando la versione 1.3.2 di jQuery, usando la versione precedente, la 1.2.6 pare che invece questo problema non sia presente, infatti in entrambi i casi i tempi sono paragonabili con un guadagno del 10% appena nell'utilizzo della seconda forma.
Appena avrò tempo farò anche dei test uando la versione 1.4, vedremo che sorprese ci riserva, anche in funzione dell'incremento prestazionale tanto dichiarato al momento del rilascio.

Altri contenuti che potrebbero interessarti

  • SASS per i CSS con Compass (in ruby)
    Come indicato nell'articolo precedente abbiamo visto la comodità di usare un metalinguaggio per i CSS come SASS. Ovviamente i browser non sono in grado di utilizzare direttamente questi file, ma necessitano di ricevere del codice CSS standard. Questa operazione (NdA:la conversione da SASS a CSS)...
  • Nello sviluppo di siti web è preferibile operare in locale e trasferire il tutto sul server remoto solo una volta che si è ottimizzata la configurazione per lo scopo che ci si è prefissi. Ciò permette di avere una maggior velocità poiché non è necessario operare sul server trasferendo i file ogni...
  • Drupal si occupa esclusivamente della validazione lato server delle informazioni, ma spesso è consigliabile prevedere ad una prima validazione dei dati inseriti dall'utente lato client, in modo da evitare l'invio della richiesta limitando quindi le possibilità di errore. Ovviamente la validazione...
  • SASS per i CSS
    I CSS sono uno degli elementi che nel corso degli anni, nel settore del web, si sono meno evoluti dal pundo ti vista della struttura utilizzata. Nelle corso delle diverse versioni sono state aggiunge solo proprietà e selettori nuovi. Probabilmente penserete: Se non sono cambiati tantomeglio, evito...

Commenti

Ritratto di Francesco

bug?

molto interessante questo post! ha sorpreso anche me (tra l'altro questo comportamento è ancora presente con jquery 1.4.2). Penso sia una sotto ottimizzazione di $() perché io ho sostituito

$('#menu-container a')

con

$('#menu-container').filter("#menu-container a")

che dovrebbero essere equivalenti, e ora le due versioni sono di nuovo equivalenti in termini di tempo (ma $('a', '#menu-container') rimane leggermente più veloce).

Ritratto di mavimo

Purtroppo confermi la mia

Purtroppo confermi la mia ipotesi, strano non sia stato rilevato da parte del QA di jQuery. Ptrebbe anche essere un problema dell'engine JS per l'elaborazione della pagina, i miei test erano stati eseguiti con FF 3.5/3.6, appena riesco proseguo facendo dei test anche con Chrome e Opera...

Ritratto di psicomante

Ciao Mavimo! ti ho risposto

Ciao Mavimo! ti ho risposto sul mio blog con un ampliamento dei test.

http://blog.psicomante.net/node/223

Invia nuovo commento





  • Elementi HTML permessi: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <h2> <h3> <h4> <table> <thead> <tbody> <tr> <th> <td>
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • Linee e paragrafi vanno a capo automaticamente.
  • Indirizzi web o e-mail vengono trasformati in link automaticamente

Maggiori informazioni sulle opzioni di formattazione.



Condividi contenuti