2012-03-06 17 views
21

sto facendo un po 'di codice javascript e mi chiedevo se il metodo di lunghezza è "precalcolato", o ricordato dal motore JS.Javascript: il metodo di lunghezza è efficiente?

Quindi, la domanda è:

Se sto controllando molto spesso per una lunghezza array, e supponendo che non sto cambiarlo (che lo rende immutabile attraverso una chiusura), dovrei precompute il metodo di lunghezza e memorizzarlo in alcune variabili?

Grazie!

+2

Non c'è 'length' ** ** metodo a built-in javascript oggetti, ma l'accesso ai beni oggetto è spesso più lento di accesso variabile locale. – kirilloid

+0

Se la differenza tra la pagina che si comporta male e l'esecuzione accettabile sono alcuni riferimenti a ".length" su istanze di array, allora hai sicuramente alcuni problemi molto più importanti da risolvere. – Pointy

+3

Perchè @Pointly? Non posso cercare ogni miglioramento nel mio codice? Non posso essere solo curioso? – santiagobasulto

risposta

6

Tutti gli interpreti principali forniscono accessor efficienti per le lunghezze degli array nativi, ma non per oggetti di tipo array come 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" suggerisce

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

Nessuno di questi sono e fficient. getElementsByTagName restituisce un oggetto dinamico, non un array statico. Ogni volta che viene controllata la condizione del ciclo, Opera deve riesaminare l'oggetto e calcolare quanti elementi a cui fa riferimento, al fine di elaborare la proprietà length. Questo richiede un po 'più di tempo rispetto al controllo di un numero statico.

+0

È vero per tutti i 'NodeList's, o solo per quelli dal vivo? –

+0

Grazie a @Mike, hai qualche codice? Forse una domanda derivata potrebbe essere: "Come vengono implementati gli array in Javascript?" – santiagobasulto

+2

Quando guardo la rete di sviluppatori di Mozilla per gli array, non vedo molte informazioni fornite per la lunghezza https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array Ma, vorrei precomputerne la lunghezza e memorizzarla in una variabile solo per essere al sicuro. Non penso che i browser condividano lo stesso motore JS –

2

Probabilmente è possibile ottenere un aumento della velocità modesto memorizzando nella cache la lunghezza in una variabile locale a causa della velocità di ricerca degli attributi. Questo può essere o non essere trascurabile, a seconda di come il JS del motore JIT codifica il codice.

Vedere http://jsperf.com/for-loop-caching per un rudimentale banco di prova JSperf.

+0

Grazie a @AKX, non considero un problema la ricerca degli attributi. Utilizzando array.length mantenere le cose leggibili. – santiagobasulto

+1

Ecco un caso di test jsperf non-così-rudimentale http://jsperf.com/caching-array-length/4 – Tomalak

+0

Buone prove! Non sto iterando su di esso però. Sto solo usando il modulo per farlo funzionare. – santiagobasulto

1

Per qualsiasi oggetto del tipo di raccolta di cui non si manipolerà la lunghezza (ad esempio una qualsiasi collezione immutabile), è sempre consigliabile memorizzarne la lunghezza per ottenere prestazioni migliori.

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

Perché? Qualsiasi codice? Penso che sia meglio usare il metodo .length, se non ci sono penalità di performance. Voglio dire, se non viene calcolato ogni volta che lo chiamo. – santiagobasulto

+1

@santiagobasulto È corretto che la proprietà 'length' non sia sempre calcolata e quindi non costi le prestazioni su alcuni browser. Tuttavia, su altri browser, la memorizzazione nella cache di una variabile è più veloce rispetto all'accesso alla proprietà 'length' in un ciclo. Vedi http://jsperf.com/for-loop-caching per ulteriori prove. Quindi scorrere verso il basso e notare che IE e Opera funzionano meglio quando si memorizza nella cache il valore 'length' invece di accedervi tramite la proprietà all'interno di un ciclo. –

21

Come sempre, la risposta è "dipende".

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 e Firefox ottimizzare la funzione di accesso proprietà di essere efficiente come copiare la lunghezza a una variabile locale. IE e Opera non lo fanno, e sono il 50% + più lenti.

Tuttavia, tenere presente che i risultati delle prove 'ops/secondo' indica il numero di iterazioni completi attraverso una matrice di un milione di elementi al secondo.

Per mettere questo in prospettiva, anche in IE8 (il peggiore esecutore di questo gruppo) — che ha segnato 44 e 3.9 sull'accesso alle proprietà e sulla variabile locale (rispettivamente) — la penalità per iterazione era scarsa 2 μs. L'iterazione di oltre mille articoli, utilizzando array.length, ti costerà solo 2 ms in più. In altre parole: attenti all'ottimizzazione prematura.

+0

+1 per metterlo in prospettiva. – Tomalak

+0

Amo questa risposta. –

+0

Il salvataggio di 2 ms per 1.000 articoli non è un'ottimizzazione prematura. Come più, cosa succede se ci sono 10.000 oggetti? Se il codice viene spesso chiamato? –

9

La lunghezza di un array effettivo non viene calcolata al volo. È memorizzato come parte della struttura dei dati dell'array, quindi l'accesso non richiede più lavoro rispetto al semplice recupero del valore (non c'è computazione). In quanto tale, generalmente sarà veloce quanto recuperare qualsiasi proprietà fissa di un oggetto. Come si può vedere in questo test le prestazioni, non v'è praticamente alcuna differenza tra il recupero della lunghezza di un array e il recupero di una proprietà di un oggetto:

http://jsperf.com/length-comparisons

Un'eccezione a questa è oggetti NodeList che i DOM rendimenti da funzioni come getElementsByTagName() o getElementsByClassName(). In questi, è spesso molto più lento accedere alla proprietà length. Ciò è probabilmente dovuto al fatto che questi oggetti nodeList non sono veri oggetti javascript e potrebbe esserci un ponte tra Javascript e codice nativo che deve essere attraversato ogni volta che si accede a qualcosa da questi oggetti. In questo caso, sarebbe molto più veloce (10-100 volte più veloce) memorizzare la lunghezza in una variabile locale piuttosto che utilizzarla ripetutamente in un loop al di fuori della lista dei nodi. L'ho aggiunto al confronto della lunghezza e puoi vedere quanto è più lento.

In alcuni browser, è significativamente più veloce inserire la lunghezza in una variabile locale e utilizzarla da lì se ci si riferisce a essa più e più volte (come in un ciclo). Ecco il grafico delle prestazioni dal test jsperf sopra:

Problemi correlati