2015-05-20 7 views
10

Say Mam następujące javascript obsługi zdarzeń:Po wprowadzeniu zmian DOM w procedurze obsługi zdarzenia JavaScript, czy zmiany są renderowane przyrostowo, czy tylko raz na końcu?

function handleEvent(e){ 
    document.body.style.backgroundColor = 'green'; 
    longRunningFunction(); 
    document.body.style.backgroundColor = 'red'; 
} 

Czy przeglądarka najpierw wyświetlić zielone tło, a następnie włącz go do czerwonego? Lub wyświetlić bezpośrednio czerwone tło?

Według moich testów wyświetla czerwony bezpośrednio na końcu obsługi zdarzenia. Ale czy jest to część specyfikacji, czy tylko przypadkowa implementacja przeglądarek?

UPDATE:

powinienem wyjaśnić, że nie jestem "celem" dla tego efektu. Przeciwnie, chcę mieć pewną gwarancję, że to się stanie , a nie. Niektóre z moich programów obsługi zdarzeń zmieniają wiele rzeczy i ułatwiają mi życie, jeśli mogę założyć, że żaden ze stanów pośrednich nie jest renderowany.

+0

Myślę, że są pewne style, które pojawią się od razu, jeśli wpłyną na układ. ogólnie rzecz biorąc, dom rzeczy dostaje się w wątku, który robi inne rzeczy. Krótki czas oczekiwania w ciągu ostatnich dwóch linii sprawiłby, że najpierw pokazałyby się zielone. – dandavis

+2

Javascript jest pojedynczy wątek, więc twój 'longRunningFunction()' będzie blokował. Niezależnie od tego, czy przerysowanie może się zdarzyć podczas działania, na pewno nie będę na nim polegać. –

Odpowiedz

11

Oto, co wydarzy się w środowisku wykonawczym javascript:

  1. document.body.style.backgroundColor zmieni jej wartość na 'green'.
  2. Uruchomiony zostanie długotrwały proces.
  3. document.body.style.backgroundColor zmieni wartość na 'red'.

Nie jest określone, w jaki sposób zmiany w właściwości backgroundColor wpłyną na wygląd strony, jeśli wątek JavaScript jest zablokowany.

Oto przykład. Jeśli klikniesz słowo hello, widać niewielkie opóźnienie, a następnie tło zmieni kolor na czerwony:

function handleEvent(e){ 
 
    document.body.style.backgroundColor = 'green'; 
 
    longRunningFunction(); 
 
    document.body.style.backgroundColor = 'red'; 
 
} 
 

 
function longRunningFunction() { 
 
    for(var i=0; i<2000000000; ++i) { +i; } 
 
} 
 

 
document.body.addEventListener("click", handleEvent);
<div>hello</div>

To dlatego, że silnik renderowania w przeglądarce, który odświeża w odpowiedzi na zmiany w CSS Właściwości blokuje długotrwała blokująca funkcja JavaScript. Nie jest to określone zachowanie, ale rzeczywistość implementacji dla wszystkich przeglądarek. Aby uzyskać podobne pytanie, patrz How can I force the browser to redraw while my script is doing some heavy processing?.

Myślę, że dowolna przeglądarka mogłaby zdecydować się na uruchomienie oddzielnego przerysowania wątku współbieżnego z wątkiem JavaScript, ale nie wierzę, że jakiekolwiek większe przeglądarki obecnie to robią. W takim podejściu mogą występować zawiłości stanu rasowego; Nigdy nie napisałem przeglądarki, więc nie wiem.


Jeśli chcesz pokazać stan pośredni, można użyć bardzo szybki setTiemout połączenia po ustawieniu backgroundColor na zielony, aby usunąć funkcję stos JavaScript i pozwalają renderujący odświeżenia strony:

function handleEvent(e){ 
    document.body.style.backgroundColor = 'green'; 
    setTimeout(function() { 
     longRunningFunction(); 
     document.body.style.backgroundColor = 'red'; 
    }, 4); 
} 

Spowoduje to dodanie do kolejki longRunningFunction i drugiej zmiany koloru, która ma potrwać 4 milisekundy w przyszłości. Podczas tych nieaktywnych 4 milisekund renderer ma szansę przerysować stronę.

+0

Dzięki. Próbuję uniknąć stanów pośrednich, by się pojawiły. Ponieważ jest to głównie luźna interfejs użytkownika (po prostu nie chcę, aby użytkownik widział migotanie), czuję się dobrze polegając na rzeczywistości obecnych implementacji, które nie są renderowane równolegle z procedurami obsługi zdarzeń. Nic złego się nie stanie, nawet jeśli się zmieni ... – user2771609

0

Czy to ilustruje, do czego dążysz?

function handleEvent(e){ 
    document.body.style.backgroundColor = 'green'; 
    alert(); 
    document.body.style.backgroundColor = 'red'; 
} 
Powiązane problemy