Rendimiento del selector jQuery
-
05-07-2019 - |
Pregunta
Tengo grandes variaciones en el rendimiento dependiendo de cómo expreso mis selectores. Por ejemplo, observe estos 2 selectores, que seleccionan exactamente los mismos elementos:
A) someTableRow.find("td.someColumnClass").find("span.editMode").find("input")
B) someTableRow.find("td.someColumnClass span.editMode input")
Esperaría que B) sea más rápido ya que solo hay 1 llamada, pero de hecho estoy encontrando que A) se ejecuta alrededor de 8 veces más rápido. No tengo idea de por qué, ¿alguien tiene alguna idea? Gracias
Solución
Suponiendo que está utilizando al menos jQuery 1.3 (es decir, con la adición de Sizzle), el rendimiento que está viendo se debe al cambio en el que se atraviesa el DOM. Desde aquí :
Hasta e incluyendo jQuery 1.2.6 el El motor del selector funcionaba en una `` arriba hacia abajo '' (o "de izquierda a derecha"). jQuery 1.3.x (es decir, Sizzle , que jQuery incorpora) introdujo un "abajo hacia arriba" ; (o " de derecha a izquierda ") enfoque de consulta el DOM.
En su segundo ejemplo ( " td.someColumnClass span.editMode input "
), Sizzle efectivamente hace esto:
- obtener todos los elementos
input
dentro desomeTableRow
- para cada elemento
input
encontrado, atraviese su árbol ancestro para elementosspan
conclass = " editMode "
. Elimine los elementosinput
que no tienen estos antepasados ?? - para cada elemento
span.editMode
encontrado, recorra su árbol ancestro para elementostd
conclass = " someColumnClass "
. Elimine los elementosinput
que no tienen estos antepasados ??
Sin embargo, en su primer ejemplo, está calificando cada paso explícitamente con cada llamada a find ()
, definiendo un contexto y atravesando abajo desde allí. Estás aplicando la "arriba-abajo" enfoque. Es equivalente a pasar a un contexto en cada paso, que es generalmente considerado un refuerzo de rendimiento :
$('input', $('span.editMode', $('td.someColumnClass', someTableRow)))
Otros consejos
Porque estás 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, se puede decidir rápidamente ignorar cualquier cosa que no sea "td.someColumnClass", entonces puede tomar ese subconjunto del DOM e ignorar cualquier cosa que no esté en "span.editMode". Por lo tanto, tiene un conjunto mucho más pequeño de elementos para buscar y encontrar " input " s ahora.
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.
La forma en que JQuery maneja los selctores es un poco diferente al CSS en mi experiencia.
Reducir el contexto a la búsqueda es la clave como señaló Josh.
Encuentro que usar los dos selectores de parámetros es realmente rápido
¿Cómo se compara esto en cuanto a velocidad?
No necesita todos los vars aquí, es solo para aclarar 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
Investigué un poco sobre jQuery Selector Performance. Un gran problema son las búsquedas por nombre de clase en Internet Explorer. IE no admite getElementsByClassName, por lo tanto, jQuery y otros marcos '' reimplement '' en JavaScript iterando a través de todos los elementos DOM. Consulte el siguiente blog de análisis sobre jQuery Selector Performance
Aquí hay un artículo realmente interesante sobre el rendimiento del selector: http: // blogs .atlassian.com / developer / 2009/08 / jquery_bondage.html
En ella, el autor muestra una "vinculación" Extensión jQuery que muestra cuántas veces se evalúa la función.