2012-05-03 9 views
55

La gente aquí a menudo sugieren para almacenar en caché el objeto jQuery creado a partir de un elemento DOM, al igual que con este código:

$('#container input').each(function() { 
    $(this).addClass('fooClass'); 
    $(this).attr('data-bar', "bar"); 
    $(this).css('background-color', 'red'); 
}); 
  • ¿Tiene almacenamiento en caché el objeto jQuery realmente mejorar el rendimiento de nuestro código?
  • ¿Qué sucede "detrás de escena" cuando pasa un elemento DOM al constructor de jQuery?
+16

'$ (this)' obviamente significa "' (this) 'dollars". – BoltClock

+0

Siempre debe almacenar en caché, pero en este ejemplo específico, ni siquiera necesita hacerlo. Solo tome ventaja de jQuery encadenando: '$ (this) .addClass ('fooClass'). Attr ('data-bar'," bar "). Css ('color de fondo', 'rojo');' –

Respuesta

51

En el jQuery tag info aparece esta advertencia:

La función de jQuery $() es caro. Llamarlo repetidamente es extremadamente ineficiente.

Bueno ... eso es cierto sólo para los selectores de cuerda, que consiguen parsean con expresiones regulares para averiguar lo que son:

quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/ 

Entonces, si la cadena es un selector (que no sea id), jQuery atraviesa el DOM para encontrar una coincidencia con su cara función find:

} else if (!context || context.jquery) { 
    return (context || rootjQuery).find(selector); 
} 

Así que sí, es caro, pero eso sólo es cierto para los selectores!

Si pasamos un DOMElement, la única acción jQuery hace es salvar el parámetro DOMElement como el contexto del objeto jQuery de nueva creación y ajuste de la longitud del contexto a 1:

// Handle $(DOMElement) 
if (selector.nodeType) { 
    this.context = this[0] = selector; // Selector here is a DOMElement 
    this.length = 1; 
    return this; 
} 

hice some tests with jsPerf , y me encontré con que, efectivamente, almacenamiento en caché el objeto jQuery tiene sólo un poco de efecto:

Bar chart, described below

En Chrome es sólo un 7% más lento. (En IE es un poco más significativa: 12%).

+24

Nota: La respuesta a sus propias preguntas es explícitamente * alentada. * Está perfectamente bien publicar una pregunta que ya sabe la respuesta si aún no aparece en el sitio. Esto de ninguna manera fomenta volver a hacer preguntas populares. Los duplicados se cerrarán y eliminarán. –

+0

En cualquier caso, está guardando al menos una llamada de función cada vez. – Christoph

+0

La comparación no es correcta ... Hay una gran diferencia en el rendimiento. –

14

para responder a su segunda pregunta, mira el source:

// Handle $(DOMElement) 
if (selector.nodeType) { 
    this.context = this[0] = selector; 
    this.length = 1; 
    return this; 
} 
+1

Aquí hay una buena aplicación para ver la fuente: http://james.padolsey.com/jquery/#v=git&fn=jQuery.fn.init – Joe

+3

Ahora, un selector de cadenas obviamente tendrá un gráfico muy diferente. – Joe

+0

@JoeTuskan. Elaboré tu comentario en mi respuesta actualizada. – gdoron

10

Con respecto a la diferencia de rendimiento, si usted está buscando una comparación directa entre los dos, es útil eliminar cualquier código adicional que pueda sesgar el resultado, como la selección DOM y otros métodos que no están directamente relacionados.

http://jsperf.com/this-cost/2

enter image description here

En un entorno de mundo más real, la diferencia relativa es menor que la prueba mostró

Otra cosa a tener en cuenta es que cada vez que se crea un objeto jQuery, la memoria debe asignarse para ello, lo que se suma al trabajo que el recolector de basura debe hacer.

Así que creo que la razón por la que la gente sugiere el almacenamiento en caché es desde un punto de vista basado en principios. Se está haciendo un trabajo adicional que, aunque generalmente no tendrá un impacto notable, en última instancia, requiere una sobrecarga que se puede evitar fácilmente.

+0

¡Buena explicación! +1 – Gaurav123

+0

Esta comparación es mucho mejor que la comparación de la respuesta aceptada. –

8

Una cosa que todas las pruebas de rendimiento en tiempo de ejecución aquí te es otra consideración importante:

ancho de banda de red.

almacenamiento en caché $(this) en una variable local disminuirá en general el tamaño de su escritura, especialmente cuando minified (porque this no puede reducirse a partir de cuatro caracteres).

considerar: la salida minified

function hello(text) { 
    $(this).attr(); 
    $(this).css(); 
    $(this).data(); 
    $(this).click(); 
    $(this).mouseover(); 
    $(this).mouseleave(); 
    $(this).html(text); 
} 
hello('Hello world'); 

Cierre del compilador es

function hello(a){$(this).attr();$(this).css();$(this).data();$(this).click();$(this).mouseover();$(this).mouseleave();$(this).html(a)}hello("Hello world"); 

Esto ahorra 39 bytes (20%). Consideremos ahora:

function hello(name) { 
    var $this = $(this); 
    $this.attr(); 
    $this.css(); 
    $this.data(); 
    $this.click(); 
    $this.mouseover(); 
    $this.mouseleave(); 
    $this.html(name); 
} 
hello('Hello world'); 

La salida minified es

function hello(b){var a=$(this);a.attr();a.css();a.data();a.click();a.mouseover();a.mouseleave();a.html(b)}hello("Hello world"); 

Esto ahorra 74 bytes (37%), casi el doble byte nuestros ahorros. Obviamente, los ahorros en el mundo real en scripts grandes serán menores, pero aún podrá obtener reducciones significativas en el tamaño de su script mediante el almacenamiento en caché.

Realmente, solo hay un lado positivo en el almacenamiento en caché $(this). Obtiene ganancias de rendimiento en tiempo de ejecución minúsculas pero mensurables. Más importante aún, puede reducir el número de bytes que viajan por el cable, y que se traduce directamente en más dólares porque faster page loads equal more sales.

Cuando se mira de esa manera, en realidad se podría decir que hay un costo en dólares cuantificable a repetir $(this) y no almacenar en caché ella.

+0

+1, aunque es más una respuesta a por qué debería cache 'this' not' $ (this) 'porque puede obtener el mismo resultado con' this.value; this.tagName; this.className; this.nodeType; esta....' – gdoron

+0

@gdoron, hay una gran diferencia entre utilizar métodos raw DOM y jQuery; no son siempre intercambiables ('addClass',' data', animation ...) Aparte de eso, todavía hay una diferencia de 3 bytes por llamada entre 'var a = $ (this); un...; a ...; 'y' var a = esto; $ (a) ...; $ (a) ...; ' – josh3736

+0

Si está comprimiendo sus archivos, a menudo encontrará que el tamaño del archivo es un poco mayor como resultado de dicho almacenamiento en caché. En su ejemplo, es solo una diferencia de unos pocos bytes, 111 vs 115 bytes, pero subraya el punto. No tengo idea de por qué es esto, pero a menudo he encontrado que este es el caso. –

Cuestiones relacionadas