2012-03-06 13 views
21

estoy haciendo algunos códigos de JavaScript y me preguntaba si el método de longitud es "precalculado", o recordado por el motor JS.Javascript: ¿El método de longitud es eficiente?

Entonces, la pregunta es:

Si estoy comprobando muy a menudo para una longitud de la matriz, y suponiendo que no estoy de cambiarlo (por lo que es inmutable a través de un cierre), que debe calcular previamente el método de longitud y almacenarlo en alguna variable?

Gracias!

+2

No hay 'length' ** ** método en una función de JavaScript objetos, pero el acceso a la propiedad objeto es a menudo más lento que acceder variable local. – kirilloid

+0

Si la diferencia entre el mal funcionamiento de su página y su rendimiento es aceptable es unas pocas referencias a ".length" en las instancias de arreglos, entonces ciertamente tiene algunos problemas mucho más importantes que resolver. – Pointy

+3

¿Por qué eso @Pointly? ¿No puedo buscar todas las mejoras en mi código? ¿No puedo ser curioso? – santiagobasulto

Respuesta

6

Todos los intérpretes importantes proporcionan accesos eficientes para las longitudes de las matrices nativas, pero no para los objetos similares a una matriz como NodeList s.

"Efficient looping in Javascript"

Test/Browser    Firefox 2.0 Opera 9.1 Internet Explorer 6 
Native For-Loop    155 (ms) 121 (ms) 160 (ms) 
... 
Improved Native While-Loop 120 (ms) 100 (ms) 110 (ms) 

"Efficient JavaScript code" sugiere

for(var i = 0; i < document.getElementsByTagName('tr').length; i++) { 
    document.getElementsByTagName('tr')[i].className = 'newclass'; 
    document.getElementsByTagName('tr')[i].style.color = 'red'; 
    ... 
} 

var rows = document.getElementsByTagName('tr'); 
for(var i = 0; i < rows.length; i++) { 
    rows[i].className = 'newclass'; 
    rows[i].style.color = 'red'; 
    ... 
} 

Ninguno de estos son correo deficiente getElementsByTagName devuelve un objeto dinámico, no una matriz estática. Cada vez que se verifica la condición de bucle, Opera tiene que volver a evaluar el objeto y calcular cuántos elementos hace referencia para calcular la propiedad length. Esto lleva un poco más de tiempo que verificar contra un número estático.

+0

¿Es eso cierto para todos los 'NodeList's, o solo para los que están en vivo? –

+0

Gracias @Mike, ¿tiene algún código? Tal vez una pregunta derivada sería: "¿Cómo se implementan las matrices en Javascript?" – santiagobasulto

+2

Cuando miro la red de desarrolladores de Mozilla para las matrices, no veo mucha información para la longitud https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array Pero, precomputaría la longitud y la almacenaría en una variable solo para estar seguro. No creo que los navegadores compartan el mismo motor JS –

2

Probablemente haya un aumento de velocidad modesto que se puede lograr almacenando en caché la longitud en una variable local debido a la velocidad de búsqueda de atributos. Esto puede o no ser insignificante, dependiendo de cómo el motor JS JIT el código.

Consulte http://jsperf.com/for-loop-caching para obtener una prueba rudimentaria de JSperf.

+0

Gracias @AKX, no considero que la búsqueda de atributos sea un problema. Usando array.length mantener las cosas legibles. – santiagobasulto

+1

Aquí hay un caso de prueba jsperf no tan rudimentario http://jsperf.com/caching-array-length/4 – Tomalak

+0

¡Buenas pruebas! Sin embargo, no estoy iterando sobre eso. Solo estoy usando su módulo para ciclarlo. – santiagobasulto

1

Para cualquier objeto de colección cuya longitud no vaya a manipular (por ejemplo, cualquier colección inmutable), siempre es una buena idea guardar en caché su longitud para obtener un mejor rendimiento.

var elems = document.getElementsByName("tst"); 
var elemsLen = elems.length; 
var i; 
for(i = 0; i < elemsLen; ++i) 
{ 
    // work with elems... example: 
    // elems[i].selected = false; 
} 
elems = [10,20,30,40,50,60,70,80,90,100]; 
elemsLen = elems.length; 
for(i = 0; i < elemsLen; ++i) 
{ 
    // work with elems... example: 
    // elems[i] = elems[i]/10; 
} 
+0

¿Por qué? ¿Algún código? Creo que es mejor usar el método .length, si no hay una penalización de rendimiento. Quiero decir, si no se computa cada vez que lo llamo. – santiagobasulto

+1

@santiagobasulto Tiene razón en que la propiedad 'longitud' no siempre se calcula y, por lo tanto, no cuesta el rendimiento en algunos navegadores. Sin embargo, en otros navegadores, el almacenamiento en memoria caché de una variable es más rápido que el acceso a la propiedad 'longitud' en un bucle. Consulte http://jsperf.com/for-loop-caching para obtener más pruebas. A continuación, desplácese hacia abajo y observe que IE y Opera funcionan mejor cuando almacenan en caché el valor de 'longitud' en lugar de acceder a él a través de la propiedad dentro de un bucle. –

21

Como siempre, la respuesta es "depende".

Let's test native arrays with a million-element array:

for (var i = 0; i < arr.length; i++); 

var len=arr.length; 
for (var i = 0; i < len; i++); 

http://josh3736.net/images/arrlen.png

Chrome y Firefox optimizar el acceso a la propiedad a ser tan eficiente como la copia de la longitud de una variable local. IE y Opera no, y son 50% + más lento.

Sin embargo, tener en cuenta que 'ops/segundo' los resultados de la prueba significa número de iteraciones completa a través de una matriz de un millón de elementos por segundo.

Para poner esto en perspectiva, incluso en IE8 (el peor desempeño en este grupo) — que anotó .44 y 3.9 en acceso de propiedad y variable local (respectivamente) — la penalización por iteración fue escasa 2 μs. Iterar más de mil elementos, usar array.length solo le costará 2 ms extra. En otras palabras: tenga cuidado con la optimización prematura.

+0

+1 para ponerlo en perspectiva. – Tomalak

+0

Me encanta esta respuesta. –

+0

Guardar 2 ms para 1,000 elementos no es una optimización prematura. Como más, ¿qué pasa si hay 10,000 artículos? Si el código se llama con frecuencia? –

9

La longitud de una matriz real no se calcula sobre la marcha. Se almacena como parte de la estructura de datos de la matriz, por lo que acceder a ella no implica más trabajo que simplemente obtener el valor (no hay cómputo). Como tal, generalmente será tan rápido como recuperar cualquier propiedad fija de un objeto. Como se puede ver en esta prueba de rendimiento, prácticamente no hay diferencia entre la recuperación de la longitud de una matriz y la recuperación de una propiedad de un objeto:

http://jsperf.com/length-comparisons

Una excepción a esto se opone la lista de nodos que los DOM retornos desde funciones como getElementsByTagName() o getElementsByClassName(). En estos, a menudo es mucho más lento acceder a la propiedad de longitud. Esto es probablemente debido a que estos objetos nodeList no son verdaderos objetos javascript y puede haber un puente entre Javascript y código nativo que debe cruzarse cada vez que se accede a algo desde estos objetos. En este caso, sería MUCHO más rápido (10-100x más rápido) almacenar en caché la longitud en una variable local en lugar de usarla repetidamente en un bucle fuera de la lista de nodos. Lo agregué a la comparación de tallas y puede ver cuánto más lento es.

En algunos navegadores, es significativamente más rápido poner la longitud en una variable local y usarla desde allí si se va a referir a ella una y otra vez (como en un bucle). Aquí está el gráfico de rendimiento de la prueba jsperf arriba:

Cuestiones relacionadas