2011-01-15 11 views
7

Me preguntaba si el otro día al escribir sus selectores en jQuery marcaría una diferencia en el rendimiento si especifica los selectores muy específicos o muy poco.selector de optimización de jQuery

Ej

$('$myId .someElement') 

O

$('table#myId > tbody > tr > td > div.someElement'); 

¿La segunda opción es mucho más rápido, o sería la diferencia es despreciable, por ejemplo cuando se hace .each() si necesita encontrar el mismo elemento de una y otra .

Respuesta

4

me inclinaría por:

$('.someElement', '#myId') 

Desde getElemenById es la operación más rápida de selección, que está filtrando primero su contenido y luego la búsqueda de la clase. Además, cuantos menos selectores sean, más rápidas serán las selecciones (depende si se usan descendiente o selectores secundarios - ¡compruebe los comentarios!). Test basado en el caso de prueba @Felix.

Editar: para mejorar esta respuesta. Basado en el jQuery documentation:

Por defecto, los selectores realizan sus búsquedas dentro del DOM a partir de la raíz documento. Sin embargo, se puede dar un contexto alternativo para la búsqueda utilizando el segundo parámetro opcional para la función $().

Así que cuando se proporciona un segundo parámetro (un contexto), jQuery buscará que elemento primero y luego buscar en su interior, por lo que sería traducida a partir de:

$('.someElement', '#myId') 

Para:

$('#myId').find('.someElement') 

Ahora el truco es decir, tratar de encontrar el contenedor más cercano de su elemento que sostiene realmente una ID y ponerlo como contexto, ya que la selección de ID es más rápida. Ahora se podría decir, por qué no, entonces el uso de la segunda ya traducido uno, por que no me realmente importa mucho ya que el primero es más limpio y no es mucho más lento:

    $('.someElement', '#myId')     $('#myId').find('.someElement') 
Chrome 8.0.552    36,527          37,400 
Firefox 3.6.13    17,632          19,155 
+0

¡No esperaba este resultado, definitivamente esta es la respuesta correcta! Gracias – Michael

+0

@Michael: De nada, y por favor no marque * directamente el botón de respuesta cuando su pregunta esté activa, especialmente cuando personas como @Felix participan ;-) – ifaour

+0

: D Esto lo tomo como un cumplido :) Por cierto. resultados interesantes Pensé que '$ ('# myId .someElement')' sería más rápido en cualquier caso, ya que se puede traducir directamente a 'querySelectorAll ('$ myId .someElement')', pero parece que '$ ('# myId') .find ('. someElement') 'es mucho más rápido. Guau. –

5

Actualización 2:

En resumen algunos otros comentarios aquí. La respuesta es depende.

jQuery's selector engine Sizzle evalúa el selector de la misma manera que CSS lo hace: from right to left. Entonces, en general, es mejor ser muy específico en el lado derecho y menos específico en el lado izquierdo.

Pero también depende de la estructura del HTML y de qué tan dispersos estén los elementos que desee encontrar.

Así que si usted tiene

      a 
         | 
         ... 
         | 
         b 
       ----------------- 
       |    | 
d d d c c c c c c c c c c c c c c c c c c c 

luego de ser más específico es más rápido $('a b > c'), debido a que están reduciendo el elemento establecer temprano con b > c y no tiene que comprobar la herencia a para cada c.

Mientras que si usted tiene

      a 
         | 
         ... 
         | 
         b 
       ----------------- 
       |    | 
e e e e e e e e d d c c c c c c e e e e e e 

continuación $('a c') sería más rápido, ya que el selector es más simple y prueba de c por ser un hijo de b es redundante en este caso (por supuesto, usted podría incluso hacer $('c')).


Respuesta original:

Sin importar cuál de ellos es más rápido, si tiene que acceder a un elemento de una y otra vez, tienda de una referencia a él:

var $element = $('#myId .someElement'); 

$('some other selector').each(function() { 
    // access $element here 
}); 

The first selector seems to be a bit faster (en Chrome 8).

En los navegadores más nuevos (que admiten querySelectorAll), la diferencia probablemente no es tan grande como en los navegadores que no la admiten.

Actualización:

Creo que depende sobre todo de la cantidad de métodos incorporados jQuery puede utilizar.Así que asumiendo querySelector* no está disponible, el primer selector puede ser traducido a

document.getElementById('myId')[0].getElementsByClassName('someElement') 

Para el segundo selector, jQuery tendría que comprobar, además, si un elemento es de hecho un niño o no. Es decir. hay más procesamiento involucrado.

+0

No creo que esta sea una respuesta a la pregunta. – PeeHaa

+0

@PeeHaa: Bueno, veo dos partes en esta pregunta: 1) ¿Qué selector es más rápido? 2) Para usarlo en un bucle 'each'. Mi respuesta es que no importa cuál es más rápido ya que no debe buscar el mismo elemento una y otra vez :) Puede que no sea una respuesta directa a la pregunta, pero con suerte una buena solución para el problema real. –

+0

+1, en realidad no era la respuesta que estaba buscando, pero sí señala una parte importante en la optimización de código, almacenar en vars es mejor que hacer la llamada dentro del bucle una y otra vez. (no era nuevo para mí, por cierto;)) – Michael

-1

El segundo será más rápido, ya que sabe exactamente qué buscar en cada paso.

En este ejemplo:

$('table#myId > tbody > tr > td > div.someElement'); 

Si no hubiera tbody, o ninguna tr, td o ninguna (etc), podría atajo de la búsqueda de inmediato. Además, cada paso posterior reducirá la búsqueda (por ejemplo, no buscando dentro del <thead>). Comparar a este ejemplo:

$('#myId .someElement') 

Esto tendría que escanear cada sub-elemento de #myId.


Edición: Como FelixKing señaló, el primer ejemplo $('#myId .someElement') es en realidad más rápido . Solo marginalmente, pero aun así, más rápido, así que pensé que debería responder. Usar el selector de niños (>), a diferencia del selector de descendientes (un espacio) es el método de cruce más rápido, ya que el posible conjunto de elementos es mucho menor. Sin embargo, los navegadores modernos tienen métodos incorporados altamente optimizados que jQuery a veces puede utilizar, en realidad reduciendo el tiempo de ejecución. Entonces, como se ve en este caso particular, el "peor" es en realidad mejor, ya que los navegadores están mejor optimizados para ejecutar esa consulta en particular. En general, sin embargo, el punto original sigue en pie, especialmente si está utilizando algo que no podría ser optimizado por los navegadores (selectores personalizados, por ejemplo).

+4

¿Tiene algún resultado de referencia para eso o simplemente lo asume? Porque mis pruebas dicen algo diferente. –

+1

¡Estoy totalmente de acuerdo con @Felix! ¡No creo que el segundo sea más rápido y, de hecho, las pruebas dieron como resultado que no lo es! ... también creo (si no confundir) que es el mismo enfoque que la selección de CSS (de derecha a izquierda). – ifaour

+0

Cuando llegó la lógica, hice la misma conclusión, aunque el resultado de la prueba de @ ifaour indica algo diferente – Michael

0
'#myid .myclass' 

1) se encuentran todos los elementos que tienen la clase myclass
2) para cada uno de estos elementos, suba su cadena de antepasados ​​y deténgase si llega al antecesor #myid. Si no hay tal antecesor, descarte el elemento.

Ahora, podría muy bien ser que los navegadores optimizar este proceso, por ejemplo:

1) encontrar el elemento #myid
2) encontrar todos los elementos que tienen la clase myclass y que son descendientes del elemento #myid


table#myid > tbody > tr > td > div.mylcass 

tenga en cuenta que el prefijo del selector de ID con un selector de tipo no tiene ningún efecto, ya que los identificadores son únicos en el documento.

#myid > tbody > tr > td > div.mylcass 

Prefijando un selector de clase con un selector de tipo es mejor en cuanto a rendimiento. Por lo tanto, si conoce el tipo de elemento, le recomendamos que lo configure.

No estoy seguro acerca de los selectores de niños. Supongo que debería ser más rápido si los usas. Pero, ¿cuánto más rápido? Posiblemente neglectible? Además, se ve feo.

Considere esto:

#myid td > div.myclass 

Si #myid es un elemento de la tabla, y no tiene tablas anidadas, a continuación, este selector debe ser tan rápido como su segundo selector. Yo usaría este.

+0

Las selecciones CSS funcionan de esta manera (de derecha a izquierda), pero no creo que jQuery lo haga. – nickf

+0

@nickf Pero jQuery usa 'querySelectorAll()', ¿verdad? –

+0

@ Šime - sí * a veces *. No si la consulta es algo que querySelectorAll no puede manejar, y no si el navegador no tiene esa función. En este caso, sí lo haría, pero en general, no. – nickf