2010-10-16 11 views
23

Por lo que entiendo, agregar .first() o :first a una consulta no detiene la búsqueda DOM después de la primera coincidencia. Simplemente le dice a jQuery que retire el primer elemento de la colección combinada.¿Cómo decirle a jQuery que deje de buscar DOM cuando se encuentre el primer elemento?

Si eso es cierto, ¿hay alguna manera de detener la búsqueda DOM después del primer partido? Por ejemplo, si sé que el resultado de esta consulta siempre será un elemento único, ¿cómo se le puede decir a jQuery que no pierda tiempo buscando más?

+0

Interesante, realmente podrían mejorar el selector ': first'. Pero no creo que cueste demasiado, obtengo 3 ms en este ejemplo que tiene un selector no nativo: http://www.jsfiddle.net/W8u64/ – BrunoLM

+3

Como referencia, hubo una breve discusión sobre esto en jQuery foros. https://forum.jquery.com/topic/why-there-is-no-jquery-findone-method-or-smth-similar –

+0

y, después de esa discusión, no parece que jQuery ellos mismos harán cualquier cosa al respecto [ticket # 11785] (http://bugs.jquery.com/ticket/11785) – Hashbrown

Respuesta

11

Por lo que sé, no hay forma de hacer esto en jQuery en este momento. Lo mejor que puede hacer es $(selector).first(), donde selector es un selector de CSS estándar que no incluye ningún selector específico de Sizzle (por lo tanto, no use :first). En este caso, jQuery usa el rápido método DOM querySelectorAll en los navegadores modernos.

Usted puede conseguir la optimización de forma manual utilizando el método de querySelector DOM que se construye para seleccionar sólo el primer partido:

$.getFirst= function(selector) { 
    if ('querySelector' in document) 
     return $(document.querySelector(selector)); 
    else 
     return $(selector).first(); 
} 

sin embargo la cantidad que ahorrará al hacer esto es mucho menor que la cantidad que ahorre asegurándose de que se pueda usar querySelectorAll.

+0

¿Qué pasa si' querySelector' también funciona como 'first' - obtiene el primer elemento de una colección? :) Es extraño que jquery no use 'querySelector' en ninguna parte, ¿no sería una clara mejora para la implementación del selector': first'? – serg

+0

Sí, en algunos navegadores 'querySelector' de hecho podría implementarse usando' querySelectorAll'! Realmente no he probado el estrés, pero no esperaría mucha diferencia de ninguna manera. 'querySelectorAll' ya es mucho más rápido en comparación con todos los demás motores de selección JS que lo precedieron. – bobince

+0

El uso de jQuery de 'querySelectorAll' es una capa de cortocircuito en la parte superior de Sizzle, un poco como la función anterior. Uno podría quizás agregar una optimización para detectar ': first' al final del selector y encender eso (¡hay que probar para ver si esto realmente vale la pena!), Pero el caso general donde': first' podría estar en el medio de un selector no es factible (debido a varios problemas con los selectores de ámbito que ya a menudo detienen jQuery usando 'querySelectorAll'). – bobince

5

:first coincide solo con un elemento. es equivalente a :eq(0).

.first() reduce el conjunto de elementos coincidentes al primero en el conjunto.

por lo que usar :first parecería que es lo que necesita, pero al mirar más de cerca ambos usan selectores primero para encontrar un conjunto y luego van a usar el primero.

Hay algunos comentarios y discusiones here y here que parecen indicar que :first() no se detiene en el primer elemento.

Referencias:

http://api.jquery.com/first-selector/

http://api.jquery.com/first/

+8

Tanto el selector ': first' como el método' .first() 'crean una lista de todos los elementos coincidentes, y solo entonces toman el primer resultado, descartando el resto. El OP está buscando una optimización para evitar reunir elementos superfluos en primer lugar. – bobince

+2

@bobince: gracias amigo, me hizo investigar más y tratar de averiguar qué hay detrás de esto. –

+0

': first' y' .first() 'pueden comportarse igual, pero internamente son diferentes. ': first' nunca hace una llamada a' .eq() ' – BrunoLM

0

yo no soy un experto en las entrañas de jQuery, pero mi opinión es que el orden en que jQuery puede encontrar las cosas no es necesariamente el orden en que aparecer en el DOM. Para asegurarte de que obtienes el artículo que está primero en el DOM, jQuery obtiene todo y ordena el resultado para que se devuelva el primer elemento.

Como habrás notado, este es un problema de rendimiento. Sin embargo, no creo que puedas desactivar este comportamiento.

Lo que puede hacer es hacer sus consultas más específicas, de modo que se seleccione menos y haya menos elementos para que jQuery ordene para encontrar el primero. Por ejemplo, $ ('li: first') no es muy específico y será lento. $ ('# myList> li: first') en teoría será mucho más rápido (aunque no lo he comparado para verificarlo) porque a) solo buscará en una sola lista, yb) también se excluirán las sublistas.

Si va a utilizar todos los elementos de una selección para algo en algún punto, pero solo necesita el primero en un punto particular, entonces tiene sentido ejecutar el selector para obtener todos sus elementos y guardarlo en un var, luego use .first() para obtener el primer elemento cuando lo necesite.

var elems = $('li'), firstElem = elems.first(); 

Ahora elems contendrá el conjunto completo, y firstElem solo contendrá el primer elemento.

Por supuesto, también podría simplemente dar el primer elemento en cada grupo que tiene la intención de seleccionar una clase específica, pero esto podría considerarse una solución poco elegante.

Cuestiones relacionadas