2009-04-03 6 views
6

Sto ottimizzando le prestazioni del mio codice e sono sorpreso di scoprire che il collo di bottiglia non è l'inserimento del nodo dom, ma la selezione.Qual è il modo più veloce per ottenere un elemento dom?

Questo è veloce:

var row = jquery(rowHTML).appendTo(oThis.parentTable); 

ma la successiva ottenendo di un elemento all'interno di "riga" è lento:

var checkbox = jquery(".checkbox input", row); 

ho bisogno di ottenere la casella di controllo in ogni riga in modo da poter collegare un gestore di eventi ad esso. La selezione della casella di controllo è QUASI AL 10X COME SLOW come l'inserimento dell'intera riga genitore.

Cosa sto facendo di sbagliato qui?

+0

ummm. questo è strano Due persone mi hanno dato una soluzione funzionante, ma poi i loro post sono scomparsi. Ad ogni modo, sembra che rimuovere i nomi delle classi dai selettori acceleri le cose immensamente. La risposta di Christoph, per usare la delega degli eventi, mi sembra al momento la cosa migliore, ma è un cambiamento più grande. – morgancodes

risposta

1

Prova a inserire un nome di classe nel campo di input stesso. Potrebbe rivelarsi più veloce.

Il motivo è che il codice passa attraverso tutte le classi .checkbox, cerca di trovare il figlio di input di quell'elemento e lo restituisce. Penso che l'azione potrebbe essere il tuo colpevole.

Semplicemente cercando tutti gli elementi con la classe del campo di input, è possibile che si verifichi una certa velocità.

2
var checkbox = jquery(".checkbox input", row); 

Questo attraversa l'intero albero di dom per trovare la casella di controllo. È possibile velocizzarlo modificando il selettore su un ID che può utilizzare la funzionalità nativa getElementById del browser.

var checkbox = jquery("#checkbox input", row); 

Si potrebbe anche utilizzare la riga come punto di partenza per la ricerca DOM come nell'esempio seguente. Ora non stai ancora analizzando l'intero albero DOM per trovare l'elemento corrispondente.

var row = jquery(rowHTML).appendTo(oThis.parentTable); 
row.children(".checkbox input"); 
+0

re: attraversare l'intero albero DOM - non sta attraversando solo i nodi figli di "riga"? – annakata

+0

Ho pensato di aggiungere il secondo argomento "row" per impedire a jQuery di attraversare l'intero dom tree e farlo partire solo con il mio elemento row. Mi sbaglio? – morgancodes

+0

Hmmm, il tuo morgancodes di destra, ho intenzione di fare alcuni test. Utilizzi principalmente righe di tabella o div? – jfar

1

Provare a utilizzare Sly, ha l'accento sulle prestazioni.

2

Utilizzare la delega eventi e aggiungere un singolo gestore a un elemento padre e non alle caselle di controllo.

jQuery supporta questo tramite la funzione live().

+0

Ottima idea. Non mi era mai nemmeno venuto in mente di affrontare la gestione degli eventi in questo modo. – morgancodes

+0

@morgancodes: ho iniziato a utilizzare la delega degli eventi quasi esclusivamente per eventi di bubbling e aggiungere la maggior parte degli ascoltatori al documento (la radice della gerarchia degli eventi); potrebbe essere inefficiente (tutti gli ascoltatori sparano a prescindere dalla fonte dell'evento), ma è estremamente conveniente, ad esempio non c'è bisogno di hacks da carico – Christoph

13

manipolazione del DOM utilizza le funzioni native per eseguire semplici operazioni. I venditori di browser ottimizzano questi. Stai costruendo la riga da HTML. JQuery utilizza internamente .innerHTML per creare la raccolta che poi aggiusta il parser mega-veloce del browser.

La selezione è lenta in confronto perché il codice JS deve ripetere ripetutamente il DOM. I browser più recenti hanno una gestione delle selezioni nativa che offre notevoli accelerazioni al JS basato su selettore. Col passare del tempo questo sarà meno di un problema.

Ecco come la query in questione, $(".checkbox input", row), rompe:

  1. row.getElementsByTagName('*');
  2. for-loop attraverso ogni elemento restituito (tutti gli elementi all'interno della fila) e test di elements[i].className con /(\s|^)checkbox(\s|$)/.
  3. for-loop ogni elemento rimasto e raccogliere matched[i].getElementsByTagName('input');
  4. unica la collezione finale.

Questo è diverso per jQuery 1.3 in quanto il motore si sposta attraverso il selettore viceversa, iniziando con il recupero di tutti gli elementi di input e il test degli elementi padre.

Ricordare che i motori di selezione JS implementano molto più delle specifiche del selettore CSS di quanto sia effettivamente utilizzabile con i CSS (o implementato dai browser correnti). Sfruttando questo, e la conoscenza dei motori, possiamo ottimizzare selettore può essere ottimizzata in diversi modi:

Se sai quello che elemento digitare il .checkbox è:

$("td.checkbox input", row); 

È più veloce per il filtro prima per tipo e poi per la classe solo per quelle partite. Questo non vale per un sottogruppo di elementi molto piccolo, ma non è quasi mai il caso nella prassi.

Il test di classe singola è il più lento del comune selectors people actually use.

Più semplice selezione:

$("input[type=checkbox]", row); 

Un ciclo è più veloce di due cicli. Questo trova solo elementi di input e quindi li filtra direttamente per tipo attributo. Dal momento che gli elementi secondari/secondari non vengono mai usati, univoco può anche essere saltato (e i motori intelligenti cercheranno di farlo perché univoco è lento).

Un selettore diretto più:

$("td:first.checkbox input", row); 

Una più complessa selettore può effettivamente essere più veloce se è più diretta (YMMV).

Se possibile, spostare il contesto di ricerca fino al livello di tabella:

Con questo voglio dire che invece di scorrendo le righe, e cercando la casella di controllo in ognuno, lasciarli soli fino a dopo la loop e quindi selezionare tutti in una volta:

$("tr td:first.checkbox input", table); 

il punto di questo è quello di eliminare il sovraccarico di sparare il motore di selettore verso l'alto più volte, ma invece fare tutto in una retata. Questo è presentato qui per completezza piuttosto che qualcosa che penso possa restituire massicci aumenti di velocità.

Non selezionare:

Costruire la riga dalla bit, assegnando gli eventi, come si va.

var row = $('<tr></tr>'); 
var cell = $('<td class="checkbox"></td>').appendTo(row); 
$('<input type="checkbox" name="..."/>').appendTo(cell).click(/* ... */); 

Questo potrebbe essere impossibile per motivi di Ajax o altri modelli fuori dal vostro controllo. Inoltre, la velocità potrebbe non valere la pena trasformare il tuo codice in questo tipo di caos, ma a volte questo può avere senso.

Oppure, se nessuna di queste funzioni per te, o restituisci troppo guadagno di prestazioni, potrebbe essere il momento di ripensare completamente il metodo. È possibile assegnare un listener di eventi più in alto l'albero e afferrare gli eventi lì, invece di esempio per-elemento:

$('table').change(function(e){ 
    // you may want a faster check... 
    if ($(e.target).is('input[type=checkbox]')) { 
    // do some stuff ... 
    } 
}); 

In questo modo non si fa nulla a meno che, e fino a quando, l'utente richiede in realtà. Più veloce. :-)

+0

wow. lunga, ottima risposta. Mi servirà un minuto per digerirlo. Grazie a Borgar! – morgancodes

+0

Mi è capitato di aver scritto un motore di selezione, quindi questa è un'area in cui mi capita di sapere alcune cose. :-) – Borgar

+0

Grazie per la spiegazione approfondita –

0

Il modo più veloce per ottenere l'elemento DOM è utilizzare puro JavaScript e chiamarlo per ID.

var element = document.getElementById('element);