2013-03-05 15 views
45

L'utilizzo di $("#vacations").find("li").last() è una procedura migliore rispetto a $("#vacations li:last")?jQuery traversal è preferibile ai selettori?

sfondo e il mio pensiero:

stavo giocando con un bel interattivo try jQuery tutorial e uno dei compiti dice:

Come siete alla ricerca attraverso il codice, si nota che qualcun altro sta selezionando la ultima vacanza con: $ ("# vacanze li: last"). Tu guardi questo e pensi "Traversal farebbe così più veloce!" Dovresti agire su quei pensieri, refactoring questo codice per trovare l'ultimo li in #vacations usando invece attraversare.

Perché dovrei pensarlo? Per me l'utilizzo di selettori sembra un livello un po 'più alto del percorso. Nella mia mente quando sto specificando un selettore, spetta a jQuery come ottenere il risultato singolo di cui ho bisogno (senza bisogno di restituire risultati intermedi).

Qual è l'overhead aggiuntivo dell'utilizzo di selettori compositi? È perché l'attuale implementazione della logica dei selettori analizza solo la stringa e utilizza l'API di attraversamento? Sta analizzando una stringa che rallenta? C'è una possibilità che un'implementazione futura userà il fatto che non ha bisogno di restituire risultati intermedi e sarà più veloce di attraversare?

+7

Ecco un test eseguito da jspref.com per voi http://jsperf.com/is-jquery-traversal-preferred-over-selectors che potete testare facilmente ora è in diversi browser. – Peeyush

+0

Non pubblicare una nuova risposta perché non è pertinente, ma allo sviluppatore, entrambi sono utili: è possibile effettuare una selezione iniziale con un selettore (può essere complesso) salvando il risultato su un oggetto jQuery, quindi eseguire in modo condizionale il codice A o B, e quindi su A esegui un metodo di attraversamento e su B ne esegui uno diverso. È più facile (e meno incline agli errori) che costruire una stringa in modo condizionale per selezionare l'elemento corretto. –

risposta

21

Non c'è una risposta precisa e secca a questo, ma rispetto al selettore :last che si sta utilizzando, è un'estensione proprietaria allo standard dell'API Selectors. Per questo motivo, non è valido per l'utilizzo con il metodo nativo .querySelectorAll.

Che Sizzle fa è fondamentalmente cercare di utilizzare il selettore con .querySelectorAll, e se viene generata un'eccezione a causa di un selettore non valido, sarà di default a un puro JavaScript selezione DOM/filtraggio basato.

Ciò significa che anche i selettori come :last non consentono di aumentare la velocità della selezione DOM con il codice nativo.

Inoltre, ci sono ottimizzazioni inclusi in modo che quando il selettore è molto semplice, come solo un ID o un nome di elemento, il nativo sarà utilizzata getElementById e getElementsByTagName, che sono estremamente veloci; di solito anche più veloce di querySelectorAll.

E dal momento che il metodo .last() appena afferra l'ultimo elemento della collezione, invece di filtrare tutte le voci, che è quello filtri Sizzle normalmente fanno (almeno quelli di una), che anche darà una spinta.

IMO, tenere lontano dalle cose proprietarie. Ora che .querySelectorAll è praticamente onnipresente, ci sono dei veri vantaggi nell'utilizzare solo selettori conformi agli standard. Esegui ulteriori operazioni di filtro sul DOM.


Nel caso di $("#vacations").find("li"), non preoccuparti per i risultati intermedi. Questo utilizzerà getElementById seguito da getElementsByTagName e sarà estremamente veloce.

Se sei davvero super preoccupato per la velocità, riduci l'utilizzo di jQuery e utilizza direttamente il DOM.


Potrai trovare attualmente note nella documentazione per i selettori come :last, che si mettono in guardia la perdita di prestazioni:

Perché: ultimo è un'estensione jQuery e non fa parte della specifica CSS, le query che utilizzano :last non possono sfruttare l'aumento di prestazioni fornito dal metodo DOM querySelectorAll() nativo. Per ottenere le migliori prestazioni quando si utilizza :last per selezionare gli elementi, selezionare prima gli elementi utilizzando un puro selettore CSS, quindi utilizzare .filter(":last").

Ma non sarei d'accordo che .filter(":last") sarebbe un buon sostituto. Molto meglio sarebbero metodi come .last() che indirizzano l'elemento direttamente anziché filtrare il set. Ho la sensazione che vogliono solo che le persone continuino ad usare i loro selettori non conformi agli standard. IMO, stai meglio dimenticandoti di loro.

14

Ecco un test per la configurazione: http://jsperf.com/andrey-s-jquery-traversal

Sizzle, il motore di selezione di jQuery, analizza la stringa con regex e cerca di accelerare i selettori molto semplici utilizzando getElementById e getElementsByTagName. Se il tuo selettore è qualcosa di più complicato di #foo e img, tenterà di utilizzare querySelectorAll, che accetta solo selettori CSS validi (no :radio, :eq, :checkbox o altri pseudo-selettori jQuery specifici).

La stringa del selettore è meno leggibile e più lento, quindi non c'è davvero alcun motivo per usarlo.

Rompendo la stringa selettore verso l'alto in semplici pezzi che Sizzle può analizzare rapidamente (#id e tagname), si sta fondamentalmente solo concatenamento insieme chiamate a getElementById e getElementsByTagName, che è circa veloce come si può ottenere.

+0

buono, quindi $ ("# my_table"). Find ("tr") è molto meglio di $ ("# my_table tr") se non sono frainteso e se abbiamo 3 selettori necessari possiamo concatenarli come $ () .find(). find() e comunque avvantaggiano il motore js sul client corrente. –

+0

@vtz: Time it. Non penso che sarebbe più veloce in quel caso specifico. – Blender