Qual è il modo più veloce per scorrere un array in JavaScript?

Ho imparato dai libri che dovresti scrivere per un ciclo come questo:

for(var i=0, len=arr.length; i < len; i++){ // blah blah } 

quindi l’ arr.length non verrà calcolato ogni volta.

Altri dicono che il compilatore farà qualche ottimizzazione, quindi puoi semplicemente scrivere:

 for(var i=0; i < arr.length; i++){ // blah blah } 

Voglio solo sapere qual è il modo migliore in pratica?

Dopo aver eseguito questo test con i browser più moderni …

http://jsben.ch/y3SpC

Attualmente , la forma più veloce di loop (e secondo me la più sintatticamente ovvia).

uno standard per il loop con memorizzazione nella cache di lunghezza

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

Direi che questo è sicuramente un caso in cui apprezzo gli sviluppatori di motori JavaScript. Un tempo di esecuzione dovrebbe essere ottimizzato per chiarezza , non intelligenza .

Il modo più veloce per effettuare il loop di un array javascript è:

 var len = arr.length; while (len--) { // blah blah } 

Vedi http://blogs.oracle.com/greimer/entry/best_way_to_code_a per un confronto completo

A partire da giugno 2016 , facendo alcuni test nell’ultimo Chrome (71% del mercato dei browser a maggio 2016 e in aumento):

  • Il ciclo più veloce è un ciclo for , con o senza lunghezza di caching che offre prestazioni davvero simili. (Il ciclo for con la lunghezza memorizzata nella cache a volte fornisce risultati migliori rispetto a quello senza cache, ma la differenza è quasi trascurabile, il che significa che il motore potrebbe essere già ottimizzato per favorire lo standard e probabilmente il più semplice per il ciclo senza memorizzazione nella cache).
  • Il ciclo while con decrementi era circa 1,5 volte più lento del ciclo for.
  • Un ciclo che utilizzava una funzione di callback (come lo standard forEach) era approssimativamente 10 volte più lento del ciclo for.

Credo che questo thread sia troppo vecchio e che i programmatori ingannevoli pensino di aver bisogno di memorizzare la lunghezza, o usare reverse reverse con decrementi per ottenere prestazioni migliori, scrivendo un codice che sia meno leggibile e più incline agli errori di un semplice ciclo semplice. Pertanto, consiglio:

  • Se la tua app esegue iterazioni su molti articoli o il tuo codice loop è all’interno di una funzione che viene usata spesso, un ciclo for semplice è la risposta:

     for (var i = 0; i < arr.length; i++) { // Do stuff with arr[i] or i } 
  • Se la tua app non esegue realmente iterazioni con molti articoli o hai solo bisogno di eseguire piccole iterazioni qua e là, l'uso dello standard forEach callback o qualsiasi funzione simile dalla tua libreria JS di scelta potrebbe essere più comprensibile e meno sobject a errori, dal momento che l'ambito della variabile dell'indice è chiuso e non è necessario utilizzare parentesi, accedendo direttamente al valore dell'array:

     arr.forEach(function(value, index) { // Do stuff with value or index }); 
  • Se hai davvero bisogno di grattare alcuni millisecondi mentre iterating su miliardi di righe e la lunghezza dell'array non cambia attraverso il processo, potresti prendere in considerazione la memorizzazione nella cache della lunghezza nel ciclo for. Anche se penso che questo non sia davvero necessario al giorno d'oggi:

     for (var i = 0, len = arr.length; i < len; i++) { // Do stuff with arr[i] } 

Se l’ordine non è importante, preferisco questo stile:

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

Mette in cache la lunghezza ed è molto più breve da scrivere. Ma itererà sopra la matrice in ordine inverso.

2014 While è tornato

Pensa solo logico.

Guarda questo

 for( var index = 0 , length = array.length ; index < length ; index++ ) { //do stuff } 
  1. È necessario creare almeno 2 variabili (indice, lunghezza)
  2. È necessario verificare se l'indice è più piccolo della lunghezza
  3. Hai bisogno di aumentare l'indice
  4. il ciclo for ha 3 parametri

Ora dimmi perché questo dovrebbe essere più veloce di:

 var length = array.length; while( --length ) { //or length-- //do stuff } 
  1. Una variabile
  2. Nessun controllo
  3. l'indice è diminuito (le macchine preferiscono questo)
  4. while ha solo un parametro

Ero completamente confuso quando Chrome 28 ha dimostrato che il ciclo for è più veloce del tempo. Questo deve avere una specie di

"Uh, tutti usano il ciclo for, concentriamoci su questo quando sviluppiamo per chrome".

Ma ora, nel 2014, il ciclo while è tornato su chrome. è 2 volte più veloce, su altri browser più vecchi è sempre stato più veloce.

Ultimamente ho fatto alcuni nuovi test. Ora nel mondo reale, i codici brevi non valgono nulla e jsperf non può effettivamente eseguire correttamente il ciclo while, perché ha bisogno di ricreare l'array. La lunghezza richiede anche tempo.

NON è ansible ottenere la velocità effettiva di un ciclo while su jsperf.

è necessario creare la propria funzione personalizzata e verificarla con window.performance.now()

E sì ... non c'è modo che il ciclo while sia semplicemente più veloce.

Il vero problema è in realtà la manipolazione dom / rendering tempo / tempo di disegno o comunque vuoi chiamarlo.

Ad esempio, ho una scena su canvas in cui ho bisogno di calcolare le coordinate e le collisioni ... ciò avviene tra 10-200 MicroSeconds (non millisecondi). in realtà ci vogliono diversi millisecondi per renderizzare tutto. Lo stesso come in DOM.

MA

C'è un altro modo super performante che usa il loop for in alcuni casi ... per esempio per copiare / clonare un array

 for( var i = array.length ; i > 0 ; arrayCopy[ --i ] = array[ i ] // doing stuff ); 

Si noti la configurazione dei parametri:

  1. Come nel ciclo while sto usando solo una variabile
  2. È necessario verificare se l'indice è più grande di 0;
  3. Come puoi vedere, questo approccio è diverso dal normale per il ciclo che tutti usano, poiché faccio cose all'interno del terzo parametro e anch'io diminuisco direttamente all'interno dell'array.

Detto questo, questo conferma che macchine come il -

scrivendo che stavo pensando di renderlo un po 'più breve e rimuovere alcune cose inutili e ho scritto questo usando lo stesso stile:

 for( var i = array.length ; i-- ; arrayCopy[ i ] = array[ i ] // doing stuff ); 

Anche se è più corto, sembra che usarlo ancora una volta rallenti tutto. È 1/5 più lento del ciclo precedente e il primo.

Nota: il ; è molto importante dopo il looo senza {}

Anche se ti ho appena detto che jsperf non è il modo migliore per testare gli script ... ho aggiunto questo 2 loop qui

http://jsperf.com/caching-array-length/40

Ed ecco un'altra risposta sulle prestazioni in javascript

https://stackoverflow.com/a/21353032/2450730

Questa risposta è per mostrare modi performanti di scrivere javascript. Quindi se non riesci a leggerlo, chiedi e otterrai una risposta o leggi un libro su javascript http://www.ecma-international.org/ecma-262/5.1/

http://jsperf.com/caching-array-length/60

L’ultima revisione del test, che ho preparato (riutilizzando quella più vecchia), mostra una cosa.

La lunghezza del caching non è molto importante, ma non danneggia.

Ogni prima esecuzione del test di cui sopra (nella scheda appena aperta) offre i migliori risultati per gli ultimi 4 snippet (3 °, 5 °, 7 ° e 10 ° in classifica) in Chrome, Opera e Firefox nel mio Debian Squeeze 64-bit (il mio hardware desktop ). Le corse successive danno risultati abbastanza diversi.

Le conclusioni sul rendimento sono semplici:

  • Vai con il ciclo for (avanti) e prova usando !== invece di < .
  • Se non si deve riutilizzare l'array in un secondo momento, allora anche il loop su decrementata lunghezza e l'array distruttivo shift() -ing è efficiente.

tl; dr

Oggi (2011.10) sotto il modello sembra essere il più veloce.

 for (var i = 0, len = arr.length; i !== len; i++) { ... } 

arr.length che la cache di arr.length non è cruciale qui, quindi puoi semplicemente provare per i !== arr.length e le prestazioni non scenderanno, ma otterrai un codice più breve.


PS: So che in snippet con shift() suo risultato potrebbe essere usato invece di accedere allo 0 ° elemento, ma in qualche modo trascurato che dopo aver riutilizzato la revisione precedente (che aveva sbagliato durante i loop), e dopo non volevo perdere già ottenuto risultati.

“Migliore” come nella pura performance? o prestazioni e leggibilità?

La “migliore” prestazione pura è questa, che utilizza una cache e l’operatore di prefisso ++ (i miei dati: http://jsperf.com/caching-array-length/189 )

 for (var i = 0, len = myArray.length; i < len; ++i) { // blah blah } 

Direi che il ciclo for senza cache è il miglior bilanciamento tra tempo di esecuzione e tempo di lettura del programmatore. Ogni programmatore che ha iniziato con C / C ++ / Java non sprecherà un ms a dover leggere questo

 for(var i=0; i < arr.length; i++){ // blah blah } 

È solo il 2018 quindi un aggiornamento potrebbe essere bello …

E devo davvero essere in disaccordo con la risposta accettata . ecco un punto di riferimento su tutti i metodi http://jsben.ch/mW36e

 arr.forEach( a => { // ... } 

e sice puoi vedere un sacco di for-loop like for(a = 0; ... ) quindi vale la pena menzionare che senza le variabili ‘var’ verranno definite globalmente e questo può influenzare notevolmente la velocità in modo che diventi 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 `
` + `${title}  ` + ` ${Number(time.toFixed(3))}msec` + `
`; } var strRes = times.map( t => template(...t) ).join("\n") + `

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; } 
 

** Memorizza la lunghezza dell’array all’interno del ciclo, alcuni secondi di tempo saranno elusi. Dipende dagli elementi dell’array se ci sono più elementi nell’array c’è una grande differenza rispetto a Ms of time *

**

 sArr; //Array[158]; for(var i = 0 ; i  

**

**

 sArr; //Array[158]; for(var i = 0,len = sArr.length ; i < len ; i++) { callArray(sArr[i]); //function call } ***end: 1.354ms*** 

**

Questo sembra essere il modo più veloce di gran lunga …

 var el; while (el = arr.shift()) { el *= 2; } 

Prendi in considerazione che questo consumerà la matrice, mangiandola e lasciando nulla lasciato …

Scrivo sempre nel primo stile.

Anche se un compilatore è abbastanza intelligente da ottimizzarlo per gli array, ma è comunque intelligente se stiamo usando DOMNodeList qui o qualche object complicato con lunghezza calcasting?

So qual è la domanda sugli array, ma penso che sia una buona pratica scrivere tutti i loop in un unico stile.

È l’anno 2017 .

Ho fatto alcuni test.

https://jsperf.com/fastest-way-to-iterate-through-an-array/

Sembra che il metodo while sia il più veloce su Chrome.

Sembra che il decremento a sinistra ( --i ) sia molto più veloce degli altri ( ++i , i-- , i++ ) su Firefox.

Questo approccio è il digiuno in media. Ma itera l’array in ordine inverso.

 let i = array.length; while (--i >= 0) { doSomething(array[i]); } 

Se l’ordine di inoltro è importante, utilizzare questo approccio.

 let ii = array.length; let i = 0; while (i < ii) { doSomething(array[i]); ++i; } 
 var arr = []; // The array var i = 0; while (i < arr.length) { // Do something with arr[i] i++; } 

i ++ è più veloce di ++ i, --i e io--

Inoltre, è ansible salvare l'ultima riga facendo arr [i ++] l'ultima volta che è necessario accedere a i (ma questo può essere difficile da eseguire il debug).

Puoi testarlo qui (con altri test del ciclo): http://jsperf.com/for-vs-whilepop/5

La soluzione più elegante che conosco è usare la mappa.

 var arr = [1,2,3]; arr.map(function(input){console.log(input);}); 

Ho provato alcuni altri modi per iterare un enorme array e ho scoperto che dimezzare la lunghezza dell’array e poi iterare entrambe le metà in un singolo ciclo è più veloce. Questa differenza di prestazioni può essere vista durante l’elaborazione di enormi matrici .

 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++; } } 

Alcuni confronti delle prestazioni (usando timer.js) tra la lunghezza della cache per il ciclo VS il metodo di cui sopra.

http://jsfiddle.net/tejzpr/bbLgzxgo/

Un altro test di jsperf.com: http://jsperf.com/while-reverse-vs-for-cached-length

Il ciclo inverso mentre sembra essere il più veloce. L’unico problema è che mentre (–i) si fermerà a 0. Come posso accedere all’array [0] nel mio ciclo allora?

A partire da settembre 2017 questi test di jsperf mostrano il seguente schema per essere i più performanti su Chrome 60:

 function foo(x) { x; }; arr.forEach(foo); 

Qualcuno è in grado di riprodurre?

Un ciclo while di base è spesso il più veloce. jsperf.com è una fantastica sandbox per testare questi tipi di concetti.

https://jsperf.com/fastest-array-loops-in-javascript/24

Mentre il ciclo è un po ‘più veloce del ciclo.

 var len = arr.length; while (len--) { // blah blah } 

Usa invece il ciclo while

Prova questo:

 var myarray =[], i = myarray.lenght; while(i--){ // do somthing }