2013-10-08 7 views
12

poniższy kod ilustruje problem, zmiana kolejności odczytu/zapisu powoduje dużą różnicę czasu wykonania (testowane przy użyciu przeglądarki Chrome, Firefox i IE):dlaczego małe uporządkowanie operacji odczytu/zapisu DOM powoduje ogromną różnicę wydajności

// 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"; 
    }); 
} 

Oto JSFiddle dla pełnego przykładu http://jsfiddle.net/Dq3KZ/2/.

Moje wyniki dla n = 100:
wersja Powolne: ~ 35ms
Szybka wersja: ~ 2ms

dla n = 1000:
wersja Powolne: ~ 2000ms
Szybko wersja: ~ 25ms

Myślę, że jest to związane z t w każdym przypadku liczba ponownych przeglądarek. W powolnym scenariuszu następuje ponowne nadawanie dla każdej operacji zapisu. Jednak w szybkim scenariuszu proces zmiany pojawia się tylko raz na końcu. Ale nie jestem pewien i nie rozumiem, dlaczego działa to w ten sposób (gdy operacje są niezależne).

Edit: użyłem InnerText własność zamiast clientWidth i Style.Width, mam ten sam problem przy korzystaniu z Google Chrome (http://jsfiddle.net/pindexis/CW2BF/7/). Jednak w przypadku użycia InnerHTML prawie nie ma różnicy (http://jsfiddle.net/pindexis/8E5Yj/).

Edit2: I otworzyły dyskusję o problemie innerHTML/innerText dla zainteresowanych: why does replacing InnerHTML with innerText causes >15X drop in performance

Odpowiedz

8

Operacje nie są niezależne.

Konieczne jest ponowne wlewanie, gdy styl lub rozmiary treści uległy zmianie i Pozycje lub wymiary są potrzebne, ponieważ żądasz wymiaru lub dlatego, że ekran musi zostać zaktualizowany (po zakończeniu kodu).

div.clientWidth to ukryte wywołanie funkcji. Gdy zażądasz tej wartości, żądasz w rzeczywistości aktualnej wartości, a zatem, w przypadku zmiany stylu, wywołujesz natychmiastowy przepływ.

W przypadku "szybkiego", nie ma powodu, aby wykonać ponowną wymianę, dopóki ekran nie zostanie przerysowany lub nie zażądasz rozmiaru. W tym przypadku potrzebny jest tylko jeden przepływ.

+0

Czy to zmiana poprzedniej szerokości 'div' powoduje wywołanie, gdy żądane jest kolejne' div' 'clientWidth'? –

+0

Zmiana szerokości div zmienia stan reflow (patrz http://www-archive.mozilla.org/newlayout/doc/reflow.html). Ale reflow nie musi być wykonane natychmiast, tylko wtedy, gdy wynik jest potrzebny. Jeśli nie zażądasz szerokości, reflow nie pojawi się, dopóki wątek się nie skończy (pamiętaj, że naprawdę nie możesz na tym polegać, pamiętam, że notatki Opery mówiły, że reflow mógłby nastąpić wcześniej, gdyby wykonanie skryptu było długie) . A to, co się dzieje, jest trudniejsze do przewidzenia ze względu na to, że reflowsy nie zawsze są całością strony. –

+0

Należy pamiętać, że wszystko to zależy od implementacji, ale wyraźnie się zmienia i natychmiastowe odczytanie w pętli jest najgorszym możliwym przypadkiem. –

Powiązane problemy