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
Quindi è la modifica della precedente larghezza di 'div 'che fa scattare un riflusso quando viene richiesto il' clientWidth' successivo di 'div'? –
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. –
Ricorda che tutto questo dipende dall'implementazione, ma chiaramente cambiando e la lettura immediata in un ciclo è una specie di caso peggiore possibile. –