Objeto jQuery: ¿guardar en caché o no?

Tengo algunos problemas que provienen de mis códigos Javascript (JS), ya que a veces necesito acceder a los mismos elementos DOM más de una vez en la misma función. Algunos razonamientos también se proporcionan aquí .

Desde el punto de vista del rendimiento, ¿es mejor crear un objeto jQuery una vez y luego almacenarlo en caché o es mejor crear el mismo objeto jQuery a voluntad? Ejemplo:

function(){ $('selector XXX').doSomething(); //first call $('selector XXX').doSomething(); //second call ... $('selector XXX').doSomething(); // n-th call } 

o

 function(){ var obj = $('selector XXX'); obj.doSomething(); //first call obj.doSomething(); //second call ... obj.doSomething(); // n-th call } 

Supongo que la respuesta probablemente depende del valor de “n”, así que supongamos que n es un número “pequeño” (por ejemplo, 3), luego un número medio (por ejemplo, 10) y finalmente uno grande (por ejemplo, 30, como si el objeto se usa para la comparación en un ciclo for).

Gracias por adelantado.

Siempre es mejor guardar en caché el elemento, si n es mayor que 1, almacenar en caché el elemento o encadenar las operaciones (puede hacer $('#something').something().somethingelse(); para la mayoría de las operaciones de jQuery, ya que generalmente devuelven el conjunto envuelto). Por otro lado, se ha convertido en un poco estándar el nombre de las variables de caché que comienzan con un signo de dinero $ para que más adelante en el código sea evidente que está realizando una operación en un conjunto de jQuery. Entonces verás que mucha gente hace var $content = $('#content'); luego $content.find('...'); mas tarde.

El segundo es superior. Lo más importante, es más limpio. En el futuro, si desea cambiar su selector, solo necesita cambiarlo en un solo lugar. De lo contrario, debe cambiarlo en N lugares.

En segundo lugar, debería funcionar mejor, aunque un usuario solo notaría una dom muy pesada, o si invocaba mucho esa función.

Si miras esta pregunta desde una perspectiva diferente, la respuesta correcta es obvia.

En el primer caso, está duplicando la lógica de selección en cada lugar que aparece. Si cambia el nombre del elemento, debe cambiar cada ocurrencia. Esto debería ser motivo suficiente para no hacerlo. Ahora tiene dos opciones: almacenar en caché el selector del elemento o el elemento en sí. Usar el elemento como objeto tiene más sentido que usar el nombre.

En cuanto a rendimiento, creo que el efecto es insignificante. Probablemente podrá encontrar resultados de prueba para este caso de uso particular: almacenar en caché objetos jQuery vs siempre volver a seleccionarlos. El rendimiento puede convertirse en un problema si tienes un DOM grande y haces muchas búsquedas, pero necesitas verlo tú mismo si ese es el caso.

Si desea ver exactamente cuánta memoria están ocupando sus objetos, puede usar Chrome Heap Profiler y verificar allí. No sé si hay herramientas similares disponibles para otros navegadores y, probablemente, las implementaciones variarán enormemente en rendimiento, especialmente en el caso de IE, pero puede satisfacer su curiosidad.

OMI, debe usar la segunda variante, almacenar el resultado de la selección en un objeto, no tanto como para mejorar el rendimiento, sino tener la menor lógica duplicada posible.

En cuanto al almacenamiento en caché $(this) , estoy de acuerdo con la respuesta de Nick Craver . Como dijo allí, también debería usar el encadenamiento siempre que sea posible: limpia su código y resuelve su problema.

Casi siempre prefiero guardar en caché el objeto jQuery, pero el beneficio varía mucho en función de lo que está utilizando exactamente para su selector. Si está utilizando identificadores, el beneficio es mucho menor que si usa tipos de selectores. Además, no todos los selectores se crean por igual, así que intente tener eso en cuenta cuando escriba sus selectores.

Por ejemplo: $('table tr td') es un selector muy pobre. Intenta usar context o .find () y hará una GRAN diferencia.

Una cosa que me gusta hacer es colocar temporizadores en mi código para ver qué tan eficiente es.

 var timer = new Date(); // code here console.log('time to complete: ' + (new Date() - timer)); 

La mayoría de los objetos almacenados en caché se ejecutarán en menos de 2 milisegundos, mientras que los selectores totalmente nuevos tardan bastante más porque primero debe encontrar el elemento y luego realizar la operación.

En JavaScript, las funciones son generalmente efímeras, especialmente cuando están alojadas en un navegador. Sin embargo, el scope de una función podría sobrevivir a la función. Esto sucede, por ejemplo, cuando creas un cierre. Si desea evitar que se haga referencia a un objeto jQuery durante mucho tiempo, puede asignarle un null a cualquier variable que haga referencia a él cuando haya terminado con esa variable o usar indirectamente para crear sus cierres. Por ejemplo:

 var createHandler = function (someClosedOverValue) { return function () { doSomethingWith(someClosedOverValue); }; } var blah = function () { var myObject = jQuery('blah'); // We want to enable the closure to access 'red' but not keep // myObject alive, so use a special createHandler for it: var myClosureWithoutAccessToMyObject = createHandler('red'); doSomethingElseWith(myObject, myClosureWithoutAccessToMyObject); // After this function returns, and assuming doSomethingElseWith() does // not itself generate additional references to myObject, myObject // will no longer have any references and be elligible for garbage // collection. } 

Debido a que jQuery(selector) podría terminar teniendo que ejecutar algoritmos costosos o incluso recorrer un poco el árbol DOM para expresiones complejas que el navegador no puede manejar directamente, es mejor guardar en caché el objeto devuelto. Además, como otros han mencionado, para la claridad del código, es mejor guardar en caché el objeto devuelto para evitar escribir el selector varias veces. Es decir, el código DRY a menudo es más fácil de mantener que el código WET.

Sin embargo, cada objeto jQuery tiene cierta cantidad de sobrecarga. Por lo tanto, almacenar grandes matrices de objetos jQuery en variables globales probablemente sea un desperdicio, a menos que realmente necesite operar en un gran número de estos objetos y aún así tratarlos como distintos. En tal situación, puede ahorrar memoria almacenando en caché las matrices de los elementos DOM directamente y usando el constructor jQuery(DOMElement) que básicamente debería estar libre al iterar sobre ellos.

Sin embargo, como dice la gente, solo puede conocer el mejor enfoque para su caso particular al comparar diferentes enfoques. Es difícil predecir la realidad incluso cuando la teoría parece sólida ;-).