objetos - ¿Cuál es la forma más rápida de recorrer una matriz en JavaScript?
matrices en javascript html (21)
"Mejor" como en rendimiento puro? o rendimiento y legibilidad?
El "mejor" rendimiento puro es este, que utiliza un caché y el operador de prefijo ++ (mis datos: http://jsperf.com/caching-array-length/189 )
for (var i = 0, len = myArray.length; i < len; ++i) {
// blah blah
}
Yo diría que el bucle sin caché es el mejor equilibrio en el tiempo de ejecución y el tiempo de lectura del programador. Todos los programadores que empezaron con C / C ++ / Java no perderán más tiempo leyendo este.
for(var i=0; i < arr.length; i++){
// blah blah
}
Aprendí de libros que deberías escribir para un bucle como este :
for(var i=0, len=arr.length; i < len; i++){
// blah blah
}
por lo que el arr.length
no se calculará cada vez.
Otros dicen que el compilador hará una optimización de esto, así que puedes escribir:
for(var i=0; i < arr.length; i++){
// blah blah
}
¿Sólo quiero saber cuál es la mejor manera en la práctica?
** caché la longitud de la matriz dentro del bucle, algunos segundos de tiempo serán eludidos. Depende de los elementos de la matriz si hay más elementos en la matriz, hay una gran diferencia con respecto a la Ms de tiempo *
**
sArr; //Array[158];
for(var i = 0 ; i <sArr.length ; i++) {
callArray(sArr[i]); //function call
}
***end: 6.875ms***
**
**
sArr; //Array[158];
for(var i = 0,len = sArr.length ; i < len ; i++) {
callArray(sArr[i]); //function call
}
***end: 1.354ms***
**
A partir de septiembre de 2017, estas pruebas jsperf muestran que el siguiente patrón es el más eficaz en Chrome 60:
function foo(x) {
x;
};
arr.forEach(foo);
¿Alguien es capaz de reproducirse?
Después de realizar esta prueba con la mayoría de los navegadores modernos ...
Actualmente , la forma más rápida de bucle (y en mi opinión, la más obvia sintácticamente).
Un estándar para bucle con caché de longitud.
for (var i = 0, len = myArray.length; i < len; i++) {
}
Yo diría que este es definitivamente un caso en el que aplaudo a los desarrolladores de motores JavaScript. El tiempo de ejecución debe optimizarse para mayor claridad , no inteligencia .
Es el año 2017 .
Hice algunas pruebas.
https://jsperf.com/fastest-way-to-iterate-through-an-array/
Parece que el método while
es el más rápido en Chrome.
Parece que el decremento izquierdo ( --i
) es mucho más rápido que los otros ( ++i
, i--
, i++
) en Firefox.
Este enfoque es el ayuno en promedio. Pero itera la matriz en orden inverso.
let i = array.length;
while (--i >= 0) {
doSomething(array[i]);
}
Si el orden hacia adelante es importante, utilice este enfoque.
let ii = array.length;
let i = 0;
while (i < ii) {
doSomething(array[i]);
++i;
}
Es sólo 2018, por lo que una actualización podría ser agradable ...
Y realmente tengo que estar en desacuerdo con la respuesta aceptada . Aquí hay un punto de referencia en todo el método http://jsben.ch/mW36e
arr.forEach( a => {
// ...
}
y al igual que puede ver una gran cantidad de for-loop como for(a = 0; ... )
vale la pena mencionar que sin ''var'' las variables se definirán globalmente y esto puede afectar dramáticamente la velocidad, por lo que se hará lento.
var arr = new Array(11111111).fill().map((_,n)=>n);
var benches =
[ [ "empty", () => {
for(var a = 0, l = arr.length; a < l; ++a);
}]
, ["for-loop", () => {
for(var a = 0, l = arr.length; a < l; ++a)
var b = arr[a] + 1;
}]
, ["for-loop++", () => {
for(var a = 0, l = arr.length; a < l; a++)
var b = arr[a] + 1;
}]
, ["for-loop - arr.length", () => {
for(var a = 0; a < arr.length; ++a )
var b = arr[a] + 1;
}]
, ["reverse for-loop", () => {
for(var a = arr.length - 1; a >= 0; --a )
var b = arr[a] + 1;
}]
,["while-loop", () => {
var a = 0, l = arr.length;
while( a < l ) {
var b = arr[a] + 1;
++a;
}
}]
, ["reverse-do-while-loop", () => {
var a = arr.length - 1; // CAREFUL
do {
var b = arr[a] + 1;
} while(a--);
}]
, ["forEach", () => {
arr.forEach( a => {
var b = a + 1;
});
}]];
function bench(title, f) {
var t0 = performance.now();
var res = f();
return performance.now() - t0; // console.log( `${title} took ${t1-t0} millisec` );
}
var globalVarTime = bench( "for-loop without ''var''", () => {
// Here if you forget to put ''var'' so variables''ll be global
for(a = 0, l = arr.length; a < l; ++a)
var b = arr[a] + 1;
});
var times = benches.map( a => [a[0], bench(...a)] )
.sort( (a,b) => a[1]-b[1] );
var max = times[times.length-1][1];
times = times.map( a => {a[2] = (a[1]/max)*100; return a; } );
var template = (title, time, n) => {
return `<div>` +
`<span>${title} </span>` +
`<span style="width:${3+n/2}%"> ${Number(time.toFixed(3))}msec</span>` +
`</div>`;
}
var strRes = times.map( t => template(...t) ).join("/n") +
`<br><br>for-loop without ''var'' ${globalVarTime} msec.`;
var $container = document.getElementById("container");
$container.innerHTML = strRes;
body { color:#fff; background:#333; font-family:helvetica; }
body > div > div {
clear:both
}
body > div > div > span {
float:left;
width:43%;
margin:3px 0;
text-align:right;
}
body > div > div > span:nth-child(2) {
text-align:left;
background:darkorange;
}
<div id="container"> </div>
Esta parece ser la manera más rápida de lejos ...
var el;
while (el = arr.shift()) {
el *= 2;
}
Tenga en cuenta que esto consumirá la matriz, comiéndola y sin dejar nada ...
He intentado algunas otras formas de iterar una gran matriz y descubrí que reducir a la mitad la longitud de la matriz y luego iterar ambas mitades en un solo bucle es más rápido. Esta diferencia de rendimiento se puede ver al procesar enormes arreglos .
var firstHalfLen =0;
var secondHalfLen = 0;
var count2=0;
var searchterm = "face";
var halfLen = arrayLength/2;
if(arrayLength%2==halfLen)
{
firstHalfLen = Math.ceil(halfLen);
secondHalfLen=Math.floor(halfLen);
}
else
{
firstHalfLen=halfLen;
secondHalfLen=halfLen;
}
for(var firstHalfCOunter=0,secondHalfCounter = arrayLength-secondHalfLen;
firstHalfCOunter < firstHalfLen;
firstHalfCOunter++)
{
if(mainArray[firstHalfCOunter].search(new RegExp(searchterm, "i"))> -1)
{
count2+=1;
}
if(secondHalfCounter < arrayLength)
{
if(mainArray[secondHalfCounter].search(new RegExp(searchterm, "i"))> -1)
{
count2+=1;
}
secondHalfCounter++;
}
}
Algunas comparaciones de rendimiento (utilizando timer.js) entre la longitud almacenada en caché para el bucle VS el método anterior.
La forma más rápida de realizar un bucle en una matriz es mediante el uso del filtro. El método filter () crea una nueva matriz con todos los elementos que pasan la prueba implementada por la función proporcionada.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
var words = [''spray'', ''limit'', ''elite'', ''exuberant'', ''destruction'', ''present''];
const result = words.filter(word => word.length > 6);
console.log(Date().now() result);
Desde mi experiencia, siempre prefiero filtros, mapas, etc.
La manera más rápida de recorrer una matriz de javascript es:
var len = arr.length;
while (len--) {
// blah blah
}
Vea http://blogs.oracle.com/greimer/entry/best_way_to_code_a para una comparación completa
La solución más elegante que conozco es usando el mapa.
var arr = [1,2,3];
arr.map(function(input){console.log(input);});
Mientras que el bucle es un poco más rápido que para bucle.
var len = arr.length;
while (len--) {
// blah blah
}
Use while loop en su lugar
Otra prueba de jsperf.com: http://jsperf.com/while-reverse-vs-for-cached-length
El bucle en sentido inverso parece ser el más rápido. El único problema es que mientras que (--i) se detendrá en 0. Entonces, ¿cómo puedo acceder a la matriz [0] en mi bucle?
Prueba esto:
var myarray =[],
i = myarray.lenght;
while(i--){
// do somthing
}
Si el orden no es importante, prefiero este estilo:
for(var i = array.length; i--; )
Se almacena en caché la longitud y es mucho más corto para escribir. Pero iterará sobre la matriz en orden inverso.
Siempre estoy escribiendo en el primer estilo.
Incluso si un compilador es lo suficientemente inteligente como para optimizarlo para arreglos, pero ¿es inteligente si usamos DOMNodeList aquí o algún objeto complicado con longitud calculada?
Sé cuál es la pregunta acerca de los arreglos, pero creo que es una buena práctica escribir todos tus bucles en un solo estilo.
Un bucle while básico es a menudo el más rápido. jsperf.com es una gran caja de arena para probar este tipo de conceptos.
http://jsperf.com/caching-array-length/60
La última revisión de la prueba, que preparé (al reutilizar la anterior), muestra una cosa.
La longitud del almacenamiento en caché no es tan importante, pero no daña.
Cada primera ejecución de la prueba vinculada anteriormente (en la pestaña recién abierta) ofrece mejores resultados para los últimos 4 fragmentos (3º, 5º, 7º y 10º en gráficos) en Chrome, Opera y Firefox en mi Debian Squeeze de 64 bits ( mi hardware de escritorio ). Las ejecuciones posteriores dan un resultado bastante diferente.
Las conclusiones sobre el rendimiento son simples:
- Vaya con for loop (forward) y pruebe usando
!==
lugar de<
. - Si no tiene que reutilizar la matriz más tarde, entonces el bucle de longitud decrementada y la matriz de
shift()
destructiva también es eficiente.
tl; dr
Hoy en día (2011.10) debajo del patrón parece ser el más rápido.
for (var i = 0, len = arr.length; i !== len; i++) {
...
}
arr.length
cuenta que el almacenamiento en caché de arr.length
no es crucial aquí, por lo que solo puede probar i !== arr.length
y el rendimiento no disminuirá, pero obtendrá un código más corto.
PD: Sé que en el fragmento de código con shift()
podría usar su resultado en lugar de acceder al elemento 0, pero de alguna manera pasé por alto que, después de reutilizar la revisión anterior (que tenía un bucle de while incorrecto), y luego no quise perder la ya obtenida. resultados
2014 While
está de vuelta
Sólo piensa en lógica.
Mira esto
for( var index = 0 , length = array.length ; index < length ; index++ ) {
//do stuff
}
- Necesidad de crear al menos 2 variables (índice, longitud)
- Necesito comprobar si el índice es menor que la longitud.
- Necesidad de aumentar el índice.
- el bucle
for
tiene 3 parámetros
Ahora dime por qué esto debería ser más rápido que:
var length = array.length;
while( --length ) { //or length--
//do stuff
}
- Una variable
- Sin cheques
- el índice disminuye (las máquinas lo prefieren)
-
while
solo tiene un parametro
Estaba totalmente confundido cuando Chrome 28 mostró que el bucle for es más rápido que el tiempo. Esto debe tener ben algún tipo de
"Uh, todos están usando el bucle for, concentrémonos en eso cuando desarrollemos para Chrome".
Pero ahora, en 2014, el bucle while está de vuelta en Chrome. es 2 veces más rápido, en otros navegadores más antiguos siempre fue más rápido.
Últimamente hice algunas pruebas nuevas. Ahora, en el mundo real, esos códigos cortos no valen nada y jsperf no puede ejecutar correctamente el bucle while, ya que necesita recrear el array.length, que también lleva tiempo.
NO PUEDES obtener la velocidad real de un bucle while en jsperf.
necesita crear su propia función personalizada y verificar que con window.performance.now()
Y sí ... no hay forma de que el bucle while sea simplemente más rápido.
El problema real es en realidad el tiempo de manipulación / representación / dibujo del dom o como quieras llamarlo.
Por ejemplo, tengo una escena de lienzo en la que necesito calcular las coordenadas y las colisiones ... esto se hace entre 10-200 MicroSegundos (no milisegundos). en realidad toma varios milisegundos para renderizar todo. Igual que en DOM.
PERO
Hay otra forma de super rendimiento utilizando el loop
for en algunos casos ... por ejemplo, para copiar / clonar una matriz
for(
var i = array.length ;
i > 0 ;
arrayCopy[ --i ] = array[ i ] // doing stuff
);
Observe la configuración de los parámetros:
- Igual que en el bucle while, estoy usando solo una variable
- Es necesario comprobar si el índice es mayor que 0;
- Como puede ver, este enfoque es diferente en comparación con lo normal para todos los bucles que se usan, ya que hago cosas dentro del tercer parámetro y también disminuyo directamente dentro de la matriz.
Dicho esto, esto confirma que las máquinas como la -
escribí que estaba pensando en hacerlo un poco más corto y eliminar algunas cosas inútiles y escribí este usando el mismo estilo:
for(
var i = array.length ;
i-- ;
arrayCopy[ i ] = array[ i ] // doing stuff
);
Incluso si es más corto, parece que usar i
una vez más ralentiza todo. Es 1/5 más lento que el anterior for
bucle y el while
.
Nota: el ;
es muy importante después de for looo sin {}
Incluso si te acabo de decir que jsperf no es la mejor manera de probar scripts ... agregué estos 2 bucles aquí
http://jsperf.com/caching-array-length/40
Y aquí hay otra respuesta sobre el rendimiento en javascript.
https://.com/a/21353032/2450730
Esta respuesta es para mostrar formas eficaces de escribir javascript. Entonces, si no puede leer eso, pregunte y obtendrá una respuesta o lea un libro sobre javascript http://www.ecma-international.org/ecma-262/5.1/
A partir de junio de 2016 , realizar algunas pruebas en Chrome más reciente (71% del mercado de navegadores en mayo de 2016, y en aumento):
- El bucle más rápido es un bucle for , con y sin longitud de caché que ofrece un rendimiento realmente similar. (El bucle for con longitud en caché a veces ofrece mejores resultados que el que no lo tiene, pero la diferencia es casi insignificante, lo que significa que el motor ya podría estar optimizado para favorecer el bucle estándar y probablemente más directo).
- El bucle while con decrementos fue aproximadamente 1.5 veces más lento que el bucle for.
- Un bucle que utiliza una función de devolución de llamada (como el estándar para Cada), fue aproximadamente 10 veces más lento que el bucle for.
Creo que este hilo es demasiado viejo y es engañoso para los programadores pensar que necesitan almacenar la longitud del caché, o usar movimientos de desplazamiento inverso con decrementos para lograr un mejor rendimiento, escribir código que sea menos legible y más propenso a errores que un simple bucle directo. Por lo tanto, recomiendo:
Si su aplicación se repite en muchos elementos o su código de bucle está dentro de una función que se usa a menudo, la respuesta es un bucle directo para:
for (var i = 0; i < arr.length; i++) { // Do stuff with arr[i] or i }
Si su aplicación realmente no recorre muchos elementos o solo necesita hacer pequeñas iteraciones aquí y allá, el uso de la devolución de llamada estándar para cada llamada o cualquier función similar de la biblioteca de JS de su elección puede ser más comprensible y menos propenso a errores, ya que el ámbito de la variable de índice está cerrado y no necesita usar paréntesis, accediendo directamente al valor de la matriz:
arr.forEach(function(value, index) { // Do stuff with value or index });
Si realmente necesita eliminar unos pocos milisegundos mientras recorre miles de millones de filas y la longitud de su matriz no cambia a través del proceso, puede considerar almacenar la longitud en su bucle for. Aunque creo que esto no es realmente necesario hoy en día:
for (var i = 0, len = arr.length; i < len; i++) { // Do stuff with arr[i] }
var arr = []; // The array
var i = 0;
while (i < arr.length) {
// Do something with arr[i]
i++;
}
i ++ es más rápido que ++ i, --i y i--
Además, puede guardar la última línea haciendo arr [i ++] la última vez que necesite acceder a i (pero esto puede ser difícil de depurar).
Puede probarlo aquí (con otras pruebas de bucle): http://jsperf.com/for-vs-whilepop/5