2012-04-11 9 views
16

Ho visto molte discussioni riguardo al modo più veloce per selezionare un primo elemento figlio usando jQuery. Come ci si può aspettare, la proprietà firstChild DOM nativa è molto più veloce dell'utilizzo di un selettore jQuery o di una combinazione di selettori - vedere http://jsperf.com/jquery-first-child-selection-performance/6. Questo di solito non è un problema - o viene utilizzato in un luogo in cui le prestazioni non sono un grosso problema, o è abbastanza facile accedere semplicemente all'elemento DOM e usare la sua proprietà .firstChild. Tuttavia, ci sono un paio di problemi con questo:Perché jQuery non fornisce un metodo .firstChild?

  • firstChild potrebbe tornare un nodo di testo o un commento, piuttosto che un elemento, come un selettore jQuery sarebbe tornato
  • Se ho bisogno di selezionare il primo figlio di elementi multipli , Devo usare un selettore lento, o andare a un sacco di lavoro extra che itera su elementi DOM, aggiungendoli a una raccolta, quindi rimettendoli in un oggetto jQuery.

Mi sembra che il costo dell'aggiunta di un metodo firstChild alla libreria jQuery di base sarebbe molto inferiore ai vantaggi. Ho preso il mio colpo a creare un tale metodo per il mio uso:

$.fn.firstChild = function() { 
    var ret = []; 

    this.each(function() { 
     var el = this.firstChild; 

     //the DOM firstChild property could return a text node or comment instead of an element 
     while (el && el.nodeType != 1) 
      el = el.nextSibling; 

     if (el) ret.push(el); 
    }); 

    //maintain jQuery chaining and end() functionality 
    return this.pushStack(ret); 
}; 

Nei test che ho creato in http://jsperf.com/jquery-multiple-first-child-selection, questa funzione esegue più di cinque volte più veloce di qualsiasi altra opzione. I test sono basati sui test sopra menzionati, ma selezionano i primi figli di più elementi, piuttosto che un singolo elemento.

C'è qualcosa che mi manca? Una tecnica che dovrei usare? O è un problema di cui non ci si dovrebbe mai preoccupare? C'è un motivo per non includere una funzione come questa in jQuery?

risposta

12

"Perché jQuery non fornisce un metodo .firstChild?"

Feature creep, molto probabilmente.

Può essere eseguito con altri metodi, come indicato, e se le prestazioni sono un problema, è possibile estendere jQuery per quella specifica necessità come si è fatto.


È possibile migliorare le prestazioni nel codice un po 'più ...

$.fn.firstChild = function() { 
    var ret = []; 
    // use a for loop 
    for (var i = 0, len = this.length; i < len; i++) { 
     var this_el = this[i], 
      el = this_el.firstElementChild; // try firstElementChild first 
     if (!el) { 
      el = this_el.firstChild; 
      while (el && el.nodeType != 1) 
       el = el.nextSibling; 
     } 
     if (el) ret.push(el); 
    } 
    //maintain jQuery chaining and end() functionality 
    return this.pushStack(ret); 
}; 
+2

+1, non sapevo su firstElementChild. Per i curiosi, ho trovato una tabella di supporto del browser qui: http://www.quirksmode.org/dom/w3c_traversal.html – undefined

+1

Vorrei anche ricordare che ho aggiunto la funzione firstChild migliorata ai test case jsperf collegati sopra. – undefined

+0

Le persone si sono arrabbiate con me per colpa tua ... :) controlla [questo] (http://meta.stackexchange.com/q/129306/173320). – gdoron

0

Per i casi singoli elementi è possibile utilizzare il

$('.test > eq(0)') 

che sembra corrispondere quasi vostro in velocità ..

http://jsperf.com/jquery-multiple-first-child-selection/2

+2

È veloce perché è un selettore non valido, quindi in realtà non sta facendo alcuna selezione DOM.Il selettore valido è ': eq (0)', che è specifico di Sizzle, e sarà lento, specialmente considerando che senza nessun altro selettore prima di ':', stai facendo effettivamente '*: eq (0)', che selezionerà tutti gli elementi nel DOM, verificherà se sono nell'indice '0', quindi verifica se il loro genitore ha' .test'. –

+1

@amnotiam lol .. dannazione mi è mancato ... e pensavo di fare qualcosa e stavo cercando di migliorarlo ... * ridacchia *. Grazie per il testa a testa. –

+0

Prego. :) –