2013-10-08 4 views
12

il seguente codice illustra il problema, la modifica dell'ordine di lettura/scrittura causa una notevole differenza nel tempo di esecuzione (Testato utilizzando Chrome, Firefox e IE):perché un piccolo riordino delle operazioni di lettura/scrittura DOM causa un'enorme differenza di prestazioni

// read->write->read->write... 
function clearSlow(divs){ 
    Array.prototype.forEach.call(divs, function(div) { 
     contents.push(div.clientWidth); 
     div.style.width = "10px"; 
    }); 
} 
// read->read->...->write->write... 
function clearFast(divs){ 
    Array.prototype.forEach.call(divs, function(div) { 
     contents.push(div.clientWidth); 
    }); 
    Array.prototype.forEach.call(divs, function(div) { 
     div.style.width = "10px"; 
    }); 
} 

Ecco un JSFiddle per l'esempio completo http://jsfiddle.net/Dq3KZ/2/.

I miei risultati per n = 100:
versione lenta: ~ 35ms
versione veloce: ~ 2ms

per n = 1000:
versione lenta: ~ 2000ms
veloce versione: ~ 25 ms

Penso che questo sia correlato con t il numero di riflussi del browser in ciascun caso. Nello scenario lento, si verifica un riflusso per ogni operazione di scrittura. Tuttavia, nello scenario veloce, il reflow si verifica una sola volta alla fine. Ma non sono sicuro e non capisco perché funziona in quel modo (quando le operazioni sono indipendenti).

Edit: Ho usato InnerText proprietà invece di clientWidth e Style.Width, ho avuto lo stesso comportamento quando si utilizza Google Chrome (http://jsfiddle.net/pindexis/CW2BF/7/). Tuttavia, quando viene utilizzato InnerHTML, non c'è quasi nessuna differenza (http://jsfiddle.net/pindexis/8E5Yj/).

Edit2: Ho aperto una discussione sulla questione innerHTML/innerText per chi fosse interessato: why does replacing InnerHTML with innerText causes >15X drop in performance

risposta

8

Le operazioni non sono indipendenti.

Un reflow deve avvenire quando le dimensioni di stile o contenuto modificato e posizioni o sono necessari dimensioni, sia perché si richiede una quota o perché lo schermo deve essere aggiornato (quando il codice termina).

div.clientWidth è una chiamata di funzione nascosta. Quando si richiede questo valore, si richiede in effetti un valore aggiornato e quindi, al variare dello stile, si attiva un riflusso immediato.

Nel caso "veloce", non vi è alcun motivo per eseguire un reflow finché lo schermo non viene ridisegnato o se si richiede una dimensione. In questo caso è necessario solo un riflusso.

+0

Quindi è la modifica della precedente larghezza di 'div 'che fa scattare un riflusso quando viene richiesto il' clientWidth' successivo di 'div'? –

+0

La modifica della larghezza div cambia lo stato di riflusso (vedere http://www-archive.mozilla.org/newlayout/doc/reflow.html). Ma il reflow non deve essere fatto immediatamente, solo quando è necessario il risultato. Quando non richiedi la larghezza, il reflow non si verifica fino alla fine del thread (nota che non puoi davvero fare affidamento su questo, mi ricordo che le note di Opera dicevano che un reflow poteva verificarsi prima se l'esecuzione dello script era lunga) . E ciò che accade è reso più difficile da prevedere a causa del fatto che i riflessi non sono sempre di tutta la pagina. –

+0

Ricorda che tutto questo dipende dall'implementazione, ma chiaramente cambiando e la lettura immediata in un ciclo è una specie di caso peggiore possibile. –

Problemi correlati