javascript optimization loops for-loop while-loop

javascript - ¿Los bucles son realmente más rápidos en reversa?



optimization loops (30)

He escuchado esto bastantes veces. ¿Los bucles de JavaScript son realmente más rápidos al contar hacia atrás? Si es así, ¿por qué? He visto algunos ejemplos de suite de prueba que muestran que los bucles invertidos son más rápidos, ¡pero no puedo encontrar ninguna explicación de por qué!

Supongo que es porque el ciclo ya no tiene que evaluar una propiedad cada vez que se comprueba para ver si está terminado y simplemente se compara con el valor numérico final.

Es decir

for (var i = count - 1; i >= 0; i--) { // count is only evaluated once and then the comparison is always on 0. }


Depende de la ubicación de su matriz en la memoria y la proporción de aciertos de las páginas de memoria mientras está accediendo a esa matriz.

En algunos casos, el acceso a los miembros de la matriz en el orden de las columnas es más rápido que el orden de las filas debido al aumento en la proporción de aciertos.


Este chico comparó muchos bucles en javascript, en muchos navegadores. También tiene un banco de pruebas para que pueda ejecutarlas usted mismo.

En todos los casos (a menos que perdí uno en mi lectura) el ciclo más rápido fue:

var i = arr.length; //or 10 while(i--) { //... }


En primer lugar, i++y i--tener exactamente el mismo tiempo en cualquier lenguaje de programación, incluyendo JavaScript.

El siguiente código tomar tiempo muy diferente.

Rápido:

for (var i = 0, len = Things.length - 1; i <= len; i++) { Things[i] };

Lento:

for (var i = 0; i <= Things.length - 1; i++) { Things[i] };

Por lo tanto el siguiente código tomar tiempo diferente también.

Rápido:

for (var i = Things.length - 1; i >= 0; i--) { Things[i] };

Lento:

for (var i = 0; i <= Things.length - 1; i++) { Things[i] };

PS lento es lento sólo para unos pocos idiomas (motores de JavaScript) debido a la optimización del compilador. La mejor manera es utilizar ''<'' en lugar ''<='' (o ''='') y ''--i'' en lugar ''i--'' .


No mucho tiempo es consumido por yo-- o i ++. Si uno se adentra en el interior de la arquitectura de la CPU del ++es más rápido que el --, ya que la --operación va a hacer el complemento a 2, pero sucedió dentro del hardware, así que esto hará que sea rápido y hay gran diferencia entre el ++y --también estas operaciones se consideran de la menos tiempo consumido en la CPU.

El bucle se ejecuta la siguiente manera:

  • Inicializar la variable una vez al comienzo.
  • Compruebe la restricción en el segundo operando del circuito, <, >, <=, etc.
  • A continuación, aplicar el bucle.
  • Incrementar el bucle y bucle de nuevo tirar de nuevo estos procesos.

Asi que,

for (var i = Things.length - 1; i >= 0; i--) { Things[i] };

calculará la longitud de la matriz solamente una vez al principio y esto no es mucho tiempo, pero

for(var i = array.length; i--; )

calculará la longitud en cada bucle, por lo que va a consumir mucho tiempo.


Puede ser explicado por JavaScript (y todos los idiomas) eventualmente convirtiéndose en códigos de operación para ejecutarse en la CPU. Las CPU siempre tienen una sola instrucción para comparar contra cero, que es muy rápido.

Como comentario, si puedes garantizar que el count siempre es >= 0 , puedes simplificarlo a:

for (var i = count; i--;) { // whatever }


Me encanta, un montón de marcas de arriba, pero no hubo respuesta: D

En pocas palabras una comparación contra cero es siempre la comparación más rápido

Así que (a == 0) es en realidad más rápido a devolver cierto que (a == 5)

Es pequeño e insignificante y con 100 millones de filas en una colección que es medible.

es decir, en un bucle hasta se le puede decir donde i <= Array.length y puede incrementar i

en un bucle hacia abajo se le puede decir donde i> = 0 y ser decremento i en su lugar.

La comparación es más rápido. No es la ''dirección'' del bucle.


La forma en que lo está haciendo ahora no es más rápido (aparte de que es un bucle indefinido, supongo que se pretende hacer i--.

Si desea hacerlo más rápido hacer:

for (i = 10; i--;) { //super fast loop }

por supuesto que no se daría cuenta de que en un pequeño bucle de este tipo. La razón por la que es más rápido se debe a que está disminuyendo i durante la comprobación de que es "verdadero" (que se evalúa como "falso" cuando llega a 0)


La mejor manera de responder a esta clase de pregunta es realmente probarlo. Establecer un bucle que cuenta con un millón de iteraciones o lo que sea, y hacerlo en ambos sentidos. Tiempo ambos bucles, y comparar los resultados.

La respuesta probablemente dependerá del navegador que está utilizando. Algunos tendrán diferentes resultados que otros.


En muchos casos, esto no tiene prácticamente nada que ver con el hecho de que los procesadores pueden comparar a cero más rápido que otras comparaciones.

Esto se debe a que sólo unos pocos motores de Javascript (los que están en la lista JIT) en realidad generan código de lenguaje de máquina.

La mayoría de los motores de JavaScript construir una representación interna del código fuente que luego interpretan (para tener una idea de lo que es esto, tener una mirada en la parte inferior de esta página en SpiderMonkey de Firefox ). En general, si un trozo de código que hace prácticamente lo mismo, pero conduce a una representación interna más simple, se ejecutará más rápido.

Hay que tener en cuenta que con tareas simples como la adición / sustracción de uno de una variable, o la comparación de una variable a otra, la sobrecarga del intérprete pasar de una "instrucción" interna a la siguiente es bastante alto, por lo que las "instrucciones" menos que sean utilizado internamente por el motor de JS, mejor.


Otros ayudan a evitar una HEADACHE --- VOTAR ESTE ARRIBA !!!

La respuesta más popular en esta página no funciona en Firefox 14 y no pasa la jsLinter. "Mientras que" bucles necesitan un operador de comparación, no una asignación. No funciona en Chrome, Safari, e incluso es decir. Pero muere en Firefox.

¡ESTO ESTÁ DESCOMPUESTO!

var i = arr.length; //or 10 while(i--) { //... }

Esto funcionará! (Funciona en Firefox, pasa el jsLinter)

var i = arr.length; //or 10 while(i>-1) { //... i = i - 1; }


i-- es tan rápido como i++

Este código a continuación es tan rápido como el suyo, pero usa una variable adicional:

var up = Things.length; for (var i = 0; i < up; i++) { Things[i] };

La recomendación es NO evaluar el tamaño de la matriz cada vez. Para arreglos grandes, uno puede ver la degradación del rendimiento.


A veces, hacer algunos cambios muy pequeños en la forma en que escribimos nuestro código puede marcar una gran diferencia en la rapidez con la que se ejecuta nuestro código. Un área donde un cambio de código menor puede hacer una gran diferencia en los tiempos de ejecución es cuando tenemos un bucle for que procesa una matriz. Cuando la matriz contiene elementos en la página web (como los botones de opción), el cambio tiene el mayor efecto, pero vale la pena aplicar este cambio incluso cuando la matriz es interna al código JavaScript.

La forma convencional de codificar un bucle for para procesar una matriz lis de esta manera:

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

El problema con esto es que evaluar la longitud de la matriz usando myArray.length lleva tiempo y la forma en que hemos codificado el ciclo significa que esta evaluación debe realizarse en todo momento alrededor del ciclo. Si la matriz contiene 1000 elementos, la longitud de la matriz se evaluará 1001 veces. Si estábamos buscando en los botones de radio y tuvimos myForm.myButtons.length entonces tomará más tiempo para evaluar desde el grupo apropiado de los botones dentro de la forma especificada en primer lugar debe estar ubicado antes de la longitud puede ser evaluado cada vez que alrededor del bucle.

Obviamente no esperamos que la longitud de la matriz para cambiar mientras estamos procesando por lo que todos estos nuevos cálculos de la duración se acaba de añadir innecesariamente al tiempo de procesamiento. (Por supuesto, si usted tiene código dentro del bucle que se agrega o se quita entradas de matriz entonces el tamaño de la matriz pueden cambiar entre las iteraciones y lo que no podemos cambiar el código que pone a prueba para ello)

Lo que podemos hacer para corregir esto por un bucle en el que se fija el tamaño es evaluar la longitud una vez al inicio del bucle y guardarlo en una variable. entonces podemos probar la variable para decidir cuándo terminar el bucle. Esto es mucho más rápido que la evaluación de la longitud de la matriz cada vez particularmente cuando la matriz contiene más que sólo unas pocas entradas o es parte de la página web.

El código para hacer esto es:

for (var i = 0, var j = myArray.length; i < j; i++) {...

Así que ahora nos limitamos a evaluar el tamaño de la matriz de una vez a prueba nuestro contador de bucle en contra de la variable que contiene el valor que cada vez alrededor del bucle. Esta variable adicional se puede acceder mucho más rápido que la evaluación del tamaño de la matriz y por lo que nuestro código se ejecutará mucho más rápido que antes. Sólo tenemos una variable adicional en nuestro script.

A menudo, no importa qué orden se procesa en la matriz, siempre y cuando todas las entradas de la matriz se procesan. Cuando este es el caso, podemos hacer que nuestro código ligeramente más rápido mediante la supresión de la variable adicional que acabamos de agregar y procesar la matriz en orden inverso.

El código final que procesa nuestra matriz en la forma más eficiente posible es:

for (var i = myArray.length-1; i > -1; i--) {...

Este código todavía sólo evalúa el tamaño de la matriz una vez al principio, pero en lugar de comparar el contador del bucle con una variable lo comparamos con una constante. Desde una constante es aún más eficaz para el acceso a una variable y ya que tenemos uno menos instrucción de asignación que antes nuestra tercera versión del código actual es ligeramente más eficiente que la segunda versión y mucho más eficiente que la primera.


He visto la misma recomendación en Sublime Text 2.

Al igual que ya se dijo, la mejora principal no es evaluar la longitud de la matriz en cada iteración en el ciclo for. Esta es una técnica de optimización bien conocida y particularmente eficiente en JavaScript cuando la matriz es parte del documento HTML (haciendo un for todos los elementos li ).

Por ejemplo,

for (var i = 0; i < document.getElementsByTagName(''li'').length; i++)

es mucho más lento que

for (var i = 0, len = document.getElementsByTagName(''li'').length; i < len; i++)

Desde donde estoy, la principal mejora en la forma de su pregunta es el hecho de que no declara una variable adicional ( len en mi ejemplo)

Pero si me preguntas, el punto no es sobre la optimización i++ vs i-- , sino sobre no tener que evaluar la longitud de la matriz en cada iteración (puedes ver una prueba de referencia en jsperf ).


++vs --no importa porque JavaScript es un lenguaje interpretado, no es un lenguaje compilado. Cada instrucción se traduce en más de un lenguaje de máquina y usted no debe preocuparse por los detalles morbosos.

Personas que están hablando acerca del uso --(o ++) para hacer un uso eficiente de las instrucciones de montaje que están mal. Estas instrucciones se aplican a la aritmética de enteros y hay no hay números enteros en JavaScript, sólo números .

Usted debe escribir código legible.


En palabras muy sencillas

"Yo-- y i ++. En realidad, son tanto se lleva al mismo tiempo".

pero en este caso cuando se tiene operación incrementales .. procesador de evaluar la .length cada variable de tiempo se incrementa en 1 y en caso de disminución .. sobre todo en este caso, se evaluará .length una sola vez hasta que lleguemos 0.


Respuesta corta

Para el código normal, especialmente en un lenguaje de alto nivel como JavaScript , no hay diferencia de rendimiento en i++ y i-- .

El criterio de rendimiento es el uso en el bucle for y la declaración de comparación .

Esto se aplica a todos los idiomas de alto nivel y es en su mayoría independiente del uso de JavaScript. La explicación es el código ensamblador resultante en la línea inferior.

Explicación detallada

Una diferencia de rendimiento puede ocurrir en un bucle. El fondo es que en el nivel del código del ensamblador puede ver que una compare with 0 es solo una declaración que no necesita un registro adicional.

Esta comparación se emite en cada pasada del ciclo y puede dar como resultado una mejora de rendimiento mensurable.

for(var i = array.length; i--; )

se evaluará a un pseudo código como este:

i=array.length :LOOP_START decrement i if [ i = 0 ] goto :LOOP_END ... BODY_CODE :LOOP_END

Tenga en cuenta que 0 es un literal, o en otras palabras, un valor constante.

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

se evaluará a un pseudo código como este (se supone la optimización normal del intérprete):

end=array.length i=0 :LOOP_START if [ i < end ] goto :LOOP_END increment i ... BODY_CODE :LOOP_END

Tenga en cuenta que el final es una variable que necesita un registro de CPU . Esto puede invocar un intercambio de registro adicional en el código y necesita una declaración de comparación más costosa en la declaración if .

Solo mis 5 centavos

Para un lenguaje de alto nivel, la legibilidad, que facilita el mantenimiento, es más importante como una mejora de rendimiento menor.

Normalmente, la iteración clásica de la matriz de principio a fin es mejor.

La iteración más rápida desde el extremo de la matriz hasta el inicio da como resultado la secuencia inversa posiblemente no deseada.

Publicar scriptum

Como se preguntó en un comentario: La diferencia de - --i i-- está en la evaluación de i antes o después de la disminución.

La mejor explicación es probarlo ;-) Aquí hay un ejemplo de Bash .

% i=10; echo "$((--i)) --> $i" 9 --> 9 % i=10; echo "$((i--)) --> $i" 10 --> 9


Esto no depende del signo -- o ++ , pero depende de las condiciones que aplique en el ciclo.

Por ejemplo: su ciclo es más rápido si la variable tiene un valor estático que si su ciclo de control estuviera en condiciones cada vez, como la longitud de una matriz u otras condiciones.

Pero no se preocupe por esta optimización, porque esta vez su efecto se mide en nanosegundos.


Intento dar una visión amplia con esta respuesta.

Los siguientes pensamientos entre corchetes fueron mi creencia hasta que acabo de probar el problema:

[[En términos de lenguajes de bajo nivel como C / C ++ , el código se compila para que el procesador tenga un comando de salto condicional especial cuando una variable es cero (o no es cero).
Además, si te importa esta optimización, puedes ir ++i lugar de i++ , porque ++i es un comando de procesador único, mientras que i++ significa j=i+1, i=j .]]

Los bucles realmente rápidos se pueden hacer desenrollándolos:

for(i=800000;i>0;--i) do_it(i);

Puede ser mucho más lento que

for(i=800000;i>0;i-=8) { do_it(i); do_it(i-1); do_it(i-2); ... do_it(i-7); }

pero las razones para esto pueden ser bastante complicadas (solo para mencionar, hay problemas con el preprocesamiento de comandos del procesador y el manejo del caché en el juego).

En términos de lenguajes de alto nivel , como JavaScript, como preguntas, puedes optimizar cosas si dependes de bibliotecas, funciones integradas para bucles. Déjelos decidir cómo se hace mejor.

En consecuencia, en JavaScript, sugeriría usar algo como

array.forEach(function(i) { do_it(i); });

También es menos propenso a errores y los navegadores tienen la posibilidad de optimizar su código.

[OBSERVACIÓN: no solo los navegadores, sino que también usted tiene un espacio para optimizarlo con facilidad, solo redefina la función forEach (dependiendo del navegador) para que utilice los mejores trucos más recientes. :) @AMK dice que en casos especiales vale la pena usar array.pop o array.shift . Si haces eso, ponlo detrás de la cortina. El exceso excesivo es agregar opciones a forEach para seleccionar el algoritmo de bucle.]

Además, también para los lenguajes de bajo nivel, la mejor práctica es usar alguna función de biblioteca inteligente para operaciones complejas en bucle, si es posible.

Esas bibliotecas también pueden poner cosas (multihilo) a sus espaldas y también los programadores especializados las mantienen actualizadas.

Hice un poco más de escrutinio y resulta que en C / C ++, incluso para 5e9 = (50,000x100,000) operaciones, no hay diferencia entre subir y bajar si las pruebas se realizan contra una constante como dice @alestanis. (Los resultados de JsPerf a veces son inconsistentes pero en general dicen lo mismo: no se puede hacer una gran diferencia).
Entonces, sucede que es más bien algo "elegante". Solo te hace ver como un mejor programador. :)

Por otro lado, para-desenrollarme en esta situación 5e9, me ha bajado de 12 segundos a 2.5 segundos cuando pasé por 10 segundos, y a 2.1 segundos cuando supere los 20 segundos. Fue sin optimización, y la optimización ha reducido las cosas a poco tiempo. :) (El desenrollado se puede hacer a mi manera arriba o usando i++ , pero eso no trae las cosas por delante en JavaScript).

En general: mantenga las i-- / i++ y ++i / i++ en las entrevistas de trabajo, array.forEach a array.forEach u otras funciones complejas de la biblioteca cuando estén disponibles. ;)


La última vez que me molesté fue cuando escribí el ensamblaje 6502 (8 bits, ¡sí!). La gran ventaja es que la mayoría de las operaciones aritméticas (especialmente decrementos) actualizaron un conjunto de indicadores, uno de ellos era Z , el indicador "llegó a cero".

Por lo tanto, al final del ciclo simplemente hizo dos instrucciones: DEC (decremento) y JNZ (salto si no es cero), ¡no se necesita comparación!


No es el -- o ++ , es la operación de comparación. Con -- puedes usar una comparación con 0, mientras que con ++ necesitas compararla con la longitud. En el procesador, comparar con cero normalmente está disponible, mientras que comparar con un entero finito requiere una resta.

a++ < length

en realidad está compilado como

a++ test (a-length)

Por lo tanto, lleva más tiempo en el procesador cuando se compila.


Para abreviar: no hay absolutamente ninguna diferencia en hacer esto en JavaScript.

En primer lugar, puede probarlo usted mismo:

No solo puede probar y ejecutar cualquier script en cualquier biblioteca de JavaScript, sino que también tiene acceso a todo el conjunto de scripts escritos previamente, así como la capacidad de ver las diferencias entre el tiempo de ejecución en diferentes navegadores en diferentes plataformas.

Por lo que puede ver, no hay diferencia entre el rendimiento en cualquier entorno.

Si desea mejorar el rendimiento de su script, puede intentar lo siguiente:

  1. Tener un var a = array.length; declaración para que no esté calculando su valor cada vez en el ciclo
  2. Do loop larolándose http://en.wikipedia.org/wiki/Loop_unwinding

Pero debes entender que la mejora que puedas obtener será tan insignificante, que en su mayoría ni siquiera deberías preocuparte por ello.

Mi propia opinión por qué apareció una idea errónea (Dec vs. Inc)

Hace mucho, mucho tiempo hubo una instrucción de máquina común, DSZ (Decremento y Saltar en cero). Las personas que programaron en lenguaje ensamblador usaron esta instrucción para implementar bucles a fin de guardar un registro. Ahora estos hechos antiguos están obsoletos, y estoy seguro de que no obtendrás ninguna mejora en el rendimiento en ningún idioma con esta pseudo mejora.

Creo que la única forma en que ese conocimiento puede propagarse en nuestro tiempo es cuando lees el código de otra persona. Vea una construcción así y pregunte por qué se implementó y aquí la respuesta: "mejora el rendimiento porque se compara con cero". Te volviste desconcertado por el mayor conocimiento de tu colega y piensas usarlo para ser mucho más inteligente :-)


for(var i = array.length; i--; ) no es mucho más rápido. Pero cuando reemplaza array.length con super_puper_function() , eso puede ser significativamente más rápido (ya que se llama en cada iteración). Esa es la diferencia.

Si va a cambiarlo en 2014, no necesita pensar en la optimización. Si va a cambiarlo con "Buscar y reemplazar", no necesita pensar en la optimización. Si no tiene tiempo, no necesita pensar en la optimización. Pero ahora, tienes tiempo para pensarlo.

PD: i-- no es más rápido que i++ .


No creo que tenga sentido decir que i-- es más rápido que i++ en JavaScript.

En primer lugar , depende totalmente de la implementación del motor de JavaScript.

En segundo lugar , siempre que los constructos más simples JIT hayan sido traducidos a instrucciones nativas, entonces i++ vs i-- dependerá totalmente de la CPU que lo ejecute. Es decir, en ARM (teléfonos móviles) es más rápido bajar a 0 ya que el decremento y la comparación con cero se ejecutan en una sola instrucción.

Probablemente, pensaste que uno era un desperdicio que el otro porque el camino sugerido es

for(var i = array.length; i--; )

pero el camino sugerido no es porque uno más rápido que el otro, sino simplemente porque si escribes

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

luego, en cada array.length iteración, se tuvo que evaluar la longitud (el motor de JavaScript más inteligente quizás podría darse cuenta de que ese ciclo no cambiará la longitud de la matriz). A pesar de que parece una declaración simple, en realidad es una función que obtiene el motor de JavaScript.

La otra razón, por la que i-- podría considerarse "más rápido" es porque el motor de JavaScript necesita asignar solo una variable interna para controlar el ciclo (variable a var i ). Si comparaste con array.length o con alguna otra variable, entonces tenía que haber más de una variable interna para controlar el ciclo, y el número de variables internas es un activo limitado de un motor de JavaScript. Cuantas menos variables se utilicen en un bucle, mayor será la probabilidad de que JIT tenga una optimización. Es por eso i-- podría considerarse más rápido ...


Ya que está interesado en el tema, eche un vistazo a la publicación del blog de Greg Reimer sobre un punto de referencia de bucle de JavaScript. ¿Cuál es la forma más rápida de codificar un bucle en JavaScript? :

Creé un conjunto de pruebas de benchmarking de bucle para diferentes formas de codificación de bucles en JavaScript. Ya hay algunos de estos, pero no encontré ninguno que reconociera la diferencia entre las matrices nativas y las colecciones de HTML.

También puede realizar una prueba de rendimiento en un ciclo abriendo https://blogs.oracle.com/greimer/resource/loop-test.html (no funciona si JavaScript está bloqueado en el navegador, por ejemplo, NoScript ).

EDITAR:

Se puede realizar un benchmark más reciente creado por Milan Adamovsky en tiempo de ejecución aquí para diferentes navegadores.

Para una prueba en Firefox 17.0 en Mac OS X 10.6 obtuve el siguiente ciclo:

var i, result = 0; for (i = steps - 1; i; i--) { result += i; }

como el más rápido precedido por:

var result = 0; for (var i = steps - 1; i >= 0; i--) { result += i; }


Dado que ninguna de las otras respuestas parece responder a su pregunta específica (más de la mitad de ellas muestran ejemplos de C y hablan de idiomas de nivel inferior, su pregunta es para JavaScript) decidí escribir la mía.

Entonces, aquí tienes:

Respuesta simple: i-- es generalmente más rápido porque no tiene que ejecutar una comparación a 0 cada vez que se ejecuta, los resultados de las pruebas en varios métodos están a continuación:

Resultados de la prueba: como "probado" por este jsPerf, arr.pop() es en realidad el bucle más rápido con diferencia. Pero, centrándose en --i , i-- , i++ y ++i como lo hizo en su pregunta, aquí están jsPerf (son de múltiples jsPerf, consulte las fuentes a continuación) resultados resumidos:

--i e i-- son lo mismo en Firefox, mientras que i-- es más rápido en Chrome.

En Chrome, un bucle for ( for (var i = 0; i < arr.length; i++) ) es más rápido que i-- y --i mientras que en Firefox es más lento.

En Chrome y Firefox, un arr.length almacenado en caché es significativamente más rápido con Chrome por delante en aproximadamente 170,000 ops / seg.

Sin una diferencia significativa, ++i es más rápido que i++ en la mayoría de los navegadores, AFAIK, nunca es al revés en ningún navegador.

Resumen más arr.pop() : arr.pop() es el bucle más rápido por mucho; para los bucles mencionados específicamente, i-- es el bucle más rápido.

Fuentes: http://jsperf.com/fastest-array-loops-in-javascript/15 , http://jsperf.com/ipp-vs-ppi-2

Espero que esto responda tu pregunta.


No es que i-- es más rápido que i++ . En realidad, ambos son igualmente rápidos.

Lo que toma tiempo en ciclos ascendentes es evaluar, para cada i , el tamaño de su matriz. En este ciclo:

for(var i = array.length; i--;)

Usted evalúa .length solo una vez, cuando declara i , mientras que para este ciclo

for(var i = 1; i <= array.length; i++)

usted evalúa .length cada vez que incrementa i , cuando comprueba si i <= array.length .

En la mayoría de los casos , ni siquiera debería preocuparse por este tipo de optimización .


Hice una comparación sobre jsbench .

Como alestani señaló, una cosa que lleva tiempo en bucles ascendentes, es evaluar, para cada iteración, el tamaño de la matriz. En este bucle:

for ( var i = 1; i <= array.length; i++ )

a evaluar .lengthcada vez que incrementas i. En este:

for ( var i = 1, l = array.length; i <= l; i++ )

se evalúa .lengthsólo una vez, cuando se declara i. En este:

for ( var i = array.length; i--; )

la comparación es implícita, sucede justo antes de decremento i, y el código es muy fácil de leer. Sin embargo, lo que puede hacer una diferencia tremenda, es lo que se pone dentro del bucle.

Loop con llamada a función (definido en otra parte):

for (i = values.length; i-- ;) { add( values[i] ); }

Loop con código inline:

var sum = 0; for ( i = values.length; i-- ;) { sum += values[i]; }

Si puede inline su código, en lugar de llamar a una función, sin sacrificar la legibilidad, puede tener un bucle de un orden de magnitud más rápido!

Nota : como el navegador están convirtiéndose bueno en inlining funciones simples, que realmente depende de la complejidad de su código es. Por lo tanto, antes de optimizar el perfil, porque

  1. El cuello de botella puede estar en otra parte (Ajax, reflujo, ...)
  2. Usted puede elegir un mejor algoritmo
  3. Usted puede elegir una mejor estructura de datos

Pero recuerda:

Código está escrito para que la gente lea, y sólo incidentalmente para máquinas para su ejecución.


Bueno, no sé acerca de JavaScript, lo que realmente debe ser sólo una cuestión de reevaluación longitud de la matriz y tal vez algo que ver con las matrices asociativas (si sólo decremento, se necesitarían ser asignado improbables nuevas entradas - si la matriz es densa, es decir. alguien puede optimizar para eso).

En el montaje de bajo nivel, hay una instrucción de bucle, llamado DJNZ (decremento y salto si no es cero). Por lo que la disminución y el salto es todo en una sola instrucción, por lo que es, posiblemente, siempre tan ligeramente más rápido que INC y JL / JB (incremento, salta si es menor que / salto si más adelante). Además, la comparación contra el cero es más simple que la comparación contra otro número. Pero todo lo que es realmente marginal y depende también de la arquitectura de destino (por ejemplo, podría hacer la diferencia en el brazo en un smartphone).

Yo no esperaría que esta diferencia de nivel bajo a lo que tienen gran impacto en los lenguajes interpretados, sólo que no he visto DJNZ entre las respuestas, así que pensé que iba a compartir una idea interesante.


Esto es sólo una suposición, pero tal vez es porque es más fácil para el procesador para comparar algo con 0 (i> = 0) en lugar de con otro valor (i <Things.length).


Se utiliza para ser dicho que --i fue más rápida (en C ++), ya que sólo hay un resultado, el valor reducido. i-- necesita almacenar el valor reducido de nuevo a i y también retener el valor original como el resultado (j = i--;). En la mayoría de los compiladores de este utiliza dos registros en lugar de uno que podría causar otra variable que tiene que ser escrito en la memoria en lugar de conservarse como una variable de registro.

Estoy de acuerdo con aquellos otros que han dicho no hace ninguna diferencia en estos días.