2009-09-11 25 views
5

Estoy teniendo grandes variaciones en el rendimiento dependiendo de cómo expreso mis selectores. Por ejemplo, mirar a estos 2 selectores, que seleccionan exactamente los mismos elementos:rendimiento del selector jQuery

A) someTableRow.find("td.someColumnClass").find("span.editMode").find("input") 
B) someTableRow.find("td.someColumnClass span.editMode input") 

yo esperaría B) a ser más rápido ya que sólo hay 1 llamada, pero en realidad estoy encontrando A) ejecuta alrededor 8 veces más rápido No tengo idea de por qué, ¿alguien tiene alguna idea? Gracias

Respuesta

14

que Presumiendo están utilizando al menos jQuery 1.3 (es decir, con la adición de Arden), el rendimiento que está viendo es debido al cambio en el que el DOM es atravesado. De here:

Hasta e incluyendo jQuery 1.2.6 del motor selector trabajó en un "arriba hacia abajo" (o "de izquierda a derecha") forma. jQuery 1.3.x (es decir, Sizzle, que jQuery incorpora) introdujo un enfoque de "abajo hacia arriba" (o "de derecha a izquierda") para consultar el DOM.

En el segundo ejemplo ("td.someColumnClass span.editMode input"), Arden efectivamente hace esto:

  1. obtener todos input elementos dentro someTableRow
  2. para cada elemento input encontrados, atraviesan su árbol ancestro de span elementos con class="editMode". Quite input elementos que no tienen estos antepasados ​​
  3. para cada elemento span.editMode encontrado, recorra su árbol antepasado para elementos td con class="someColumnClass". Retire input elementos que no tienen estos antepasados ​​

En el primer ejemplo, sin embargo, su están calificando cada paso de forma explícita con cada llamada a find(), la definición de un marco y atravesar abajo desde allí. Usted está aplicando el enfoque de "arriba hacia abajo". Es equivalente a pasar en un contexto en cada paso, que es generally considered a performance booster:

$('input', $('span.editMode', $('td.someColumnClass', someTableRow))) 
+0

Gracias crescentfresh, tiene sentido. En realidad, nos hemos movido a 1.3.2 desde 1.2.6 y me confundí por qué algunos selectores previamente decentemente rápidos se volvieron más lentos (la mayoría eran más rápidos). Pregunta: ¿qué es más rápido, pasando en un contexto en cada punto o utilizando llamadas encadenadas de find()? – JonoW

+0

Son efectivamente equivalentes. $ ('foo', 'bar') en realidad se reencamina a $ ('bar'). find ('foo') en el vientre de jQuery. Supongo que llamar a find() guarda explícitamente un par de ciclos de CPU, pero nada para parpadear. Haz lo que sea más legible para tu equipo. Encuentro muy legible;) –

+0

Genial, siento que find() es más intuitivo para mí, así que lo usaré – JonoW

1

A es más llamadas, pero más simple. B es una llamada, pero más compleja. En este caso, la complejidad de la llamada supera en gran medida la cantidad de llamadas.

2

Porque está reduciendo el contexto para la búsqueda.

En el caso B, tiene que buscar a través de cada elemento DOM para ver si cumple con los criterios.

En el caso A, puede decidir rápidamente ignorar cualquier cosa que no sea "td.someColumnClass", entonces puede tomar ese subconjunto del DOM e ignorar todo lo que no esté en "span.editMode". Por lo tanto, tiene un conjunto mucho más pequeño de elementos para buscar y encontrar "entradas" ahora.

+1

¿Cómo puede "decidir rápidamente ignorar ..." sin pasar por todos los hijos DOM de someTableRow? Ambos comprueban el mismo conjunto completo de elementos secundarios, uno busca los td con algunosColumnClass, luego analiza esa lista para los tramos con editMode, luego analiza esa lista para la entrada. El otro busca los tres criterios en la misma búsqueda de la lista inicial. – billjamesdev

+0

Dado que estos dos selectores son idénticos en su significado, no veo por qué jQuery no pudo usar la misma estrategia en ambos casos. –

1

La forma en que JQuery maneja selctors es un poco diferente a CSS en mi experiencia.

Reducir el contexto a la búsqueda es la clave que Josh señaló.

encuentro con los dos selectores de parámetros muy rápidos

¿Cómo se compara la velocidad prudente?

No necesita todos los vars aquí solo para dejar en claro lo que estoy haciendo.

var columnClasses = $('.someColumnClass'); 
var tableCell = $('td', columnclasses); 
var editMode = $('.editmode', tableCell); 
var spanInside = $('span', editMode); 
var inputFinally = $('input', spanInside); 

Bondad,

Dan

1

hice una investigación en jQuery selector de rendimiento a mí mismo. Un gran problema son las búsquedas por nombre de clase en Internet Explorer. IE no es compatible con getElementsByClassName; por lo tanto, jQuery y otros marcos "lo vuelven a implementar" en JavaScript iterando a través de todos los elementos DOM. Echa un vistazo al siguiente blog de análisis sobre jQuery Selector Performance