2012-04-02 4 views
8

http://jsperf.com/testing-foreach-vs-for-looparray.forOgni esecuzione più veloce dell'iterazione nativa? Come?

Era a mia conoscenza che il Test Case 2 doveva funzionare più lentamente del Test Case 1 - Volevo vedere quanto più lentamente. Immagina la mia sorpresa quando vedo che corre più velocemente!

Cosa sta succedendo qui? Dietro le quinte l'ottimizzazione? O è. Per ogni pulitore E più veloce?

test in Chrome 18.0.1025.142 a 32 bit su Windows Server 2008 R2/7 64-bit

+1

'forEach' probabilmente ha alcune ottimizzazioni native o qualcosa del genere. –

+3

Inoltre, non stai nemmeno ricevendo il valore dall'array nel Test Case 1, stai loggando i invece di 'array [i]' –

+0

1) non devi creare l'array su ogni test, puoi definire vars che saranno accessibili su tutti i test 2) stai controllando '.length' ogni ciclo – ajax333221

risposta

7

ci sono molte ottimizzazioni di iterazione che il ciclo for manca come ad esempio:

  • cache di matrice lunghezza
  • iterate all'indietro
  • uso ++ contatore invece di contatore ++

Questi sono quelli che ho sentito e usato, sono sicuro che ce ne sono altri. Se la memoria mi serve correttamente, il ciclo iteratore all'indietro è il più veloce di tutte le strutture di looping (nella maggior parte dei browser).

Vedere this jsperf per alcuni esempi.

Modifica: collegamenti per postfix vs prefix perf test e iterating backwards. Non sono riuscito a trovare il mio riferimento per usare + = 1 invece di ++, quindi l'ho rimosso dalla lista.

+0

Ho sentito che per C che ++ i è più veloce di i ++, non so se questo vale anche per Javascript –

+0

iterate all'indietro e usando '+ = 1' invece di' ++ 'in realtà non cambia nulla in JS. – kirilloid

+0

@kirilloid + = e ++ sono due operatori completamente diversi che possono essere eseguiti a velocità diverse in diverse implementazioni del parser e il decremento rispetto all'incremento è una micro-ottimizzazione ben nota. modifico per aggiungere riferimenti. – jbabey

0

Sono quasi uguali per me in Opera. Qualcosa da notare è che il tuo condizionale in for() è array.length. Se si memorizza nella cache la lunghezza dell'array in una variabile e quindi si esegue un ciclo, si dovrebbe vedere prestazioni migliori.

1

La lettura di length da array a ogni iterazione può essere lenta, ma forEach è comonomamente più lento, poiché la chiamata di funzione non è un'operazione poco costosa in js.

PS: forEach è più lento del 14% su FF10.

+0

Penso che sia ancora importante, ma credo che le JIT abbiano reso le chiamate di funzione considerevolmente più veloci. –

+0

Anch'io =) Specialmente dopo, ho velocizzato il codice JS CPU-heavy ~ 5 volte con le funzioni appena inlining. – kirilloid

+0

Non importa quello che provo, perOgni è sempre più veloce in Chrome. – trusktr

0

Forse for for() è più lento perché il ciclo applica 'array.length' a ogni iterazione, per ottenere la lunghezza dell'array.

Prova:

var nri = array.length; 
for(var i = 0; i < nri; i++){ 
    // ... 
} 
3

UPDATE:

Un sacco di vecchi trucchi di queste risposte sono grandi per interpretare JS nei browser più vecchi.

In qualsiasi implementazione JS moderna compresi tutti i browser moderni, il nodo e le ultime visualizzazioni Web mobili, le funzioni inline possono essere memorizzate nella cache dal compilatore JIT (JS), rendendo in genere un'opzione molto più veloce per l'iterazione di array. Un tempo era l'opposto in cui solo effettuare chiamate a una funzione richiedeva ripetutamente un processo di build-up/teardown che poteva seriamente ridurre le prestazioni di un ciclo non banale.

Per prestazioni ottimali eviterei di fare riferimento a qualcosa che non è stato passato come argomento o definito all'interno della funzione stessa se non è necessario. Non sono sicuro al 100% che importi, ma potrei capire perché potrebbe.

I valori Getter che implicano qualsiasi tipo di processo di ricerca come le lunghezze degli array o le proprietà del nodo DOM sono probabilmente anche meglio conservati nella cache di una variabile.

Ma oltre a questo, proverei semplicemente a lasciare che il principio di base dell'elusione del lavoro guidi i tuoi sforzi perfetti. Pre-calcolare cose che non devono essere ricalcolate in un ciclo, o memorizzare in cache un risultato del selettore di query su var piuttosto che frugare nel DOM ripetutamente sono buoni esempi di questo. Trattare troppo duramente per trarre vantaggio dal comportamento JIT probabilmente diventerà piuttosto arcano e probabilmente non durerà nel tempo o attraverso tutte le JIT.

RISPOSTA VECCHIO:

Okay, dimentica muro di testo. punti elenco:

var i = someArray.length; //length is cached 
someArray.reverse(); //include this only if iterating in 0-(length-1) order is important 

while(i--){ 
//run a test statement on someArray[i]; 
} 
  • lunghezza viene memorizzata nella cache e immediatamente reso nell'indice

  • Il vantaggio di iterazione all'indietro JS AFAIK è di evitare un operatore logico con due operandi. In questo caso stiamo solo valutando un numero. È vero o è zero e falso.

  • Lo trovo anche elegante.