Mam nadzieję, że nie zrobię z siebie głupka, ale staram się zrozumieć, co dzieje się w tych dwóch liniach kodu:
document.body.innerHTML = 'something';
alert('something else');
Zauważam, że alert pokazuje się przed aktualizacją HTML (a może tak, ale strona nie została odświeżona / odmalowana / cokolwiek)
Sprawdź ten kod, aby zobaczyć, co mam na myśli.
Należy pamiętać, że nawet wprowadzenie alert
w setTimeout(..., 0)
nie pomaga. Wygląda na to, że innerHTML
aby faktycznie zaktualizować stronę, potrzeba więcej pętli zdarzeń .
EDYTOWAĆ:
Zapomniałem wspomnieć, że używam Chrome i nie sprawdzałem innych przeglądarek. Wygląda na to, że jest widoczny tylko w Chrome. Niemniej jednak nadal jestem zainteresowany, dlaczego tak się dzieje.
javascript
html
google-chrome
dom
apieceofbart
źródło
źródło
Odpowiedzi:
Ustawienie innerHTML jest synchroniczne, podobnie jak większość zmian, które możesz wprowadzić w DOM. Jednak renderowanie strony internetowej to inna historia.
(Pamiętaj, DOM to skrót od „Document Object Model”. To tylko „model”, reprezentacja danych. To, co użytkownik widzi na ekranie, to obraz tego, jak ten model powinien wyglądać. Zatem zmiana modelu nie jest natychmiastowa zmień obrazek - aktualizacja zajmie trochę czasu.)
Uruchamianie JavaScript i renderowanie strony internetowej faktycznie odbywa się osobno. Mówiąc w uproszczeniu, przede wszystkim z JavaScript na stronie tras (z pętli zdarzeń - sprawdź to doskonały film dla bardziej szczegółowo), a następnie po że przeglądarka renderuje żadnych zmian na stronie, aby użytkownik mógł zobaczyć. Dlatego „blokowanie” to tak wielka sprawa - wykonanie kodu wymagającego dużej mocy obliczeniowej zapobiega przejściu przeglądarki przez krok „uruchom JS” i przejście do kroku „renderuj stronę”, co powoduje zawieszanie się lub zacinanie strony.
Potok Chrome wygląda następująco:
Jak widać, cały JavaScript odbywa się jako pierwszy. Następnie strona jest stylizowana, układana, malowana i komponowana - „renderowanie”. Nie cały ten potok wykona każdą klatkę. Zależy to od tego, jakie elementy strony uległy zmianie, jeśli w ogóle, i jak należy je ponownie wyrenderować.
Uwaga:
alert()
jest również synchroniczny i wykonywany podczas kroku JavaScript, dlatego okno dialogowe z ostrzeżeniem pojawia się, zanim zobaczysz zmiany na stronie internetowej.Możesz teraz zapytać „Zaczekaj, co dokładnie jest uruchamiane w tym kroku 'JavaScript' w potoku? Czy cały mój kod działa 60 razy na sekundę?” Odpowiedź brzmi „nie” i wraca do sposobu działania pętli zdarzeń JS. Kod JS działa tylko wtedy, gdy znajduje się na stosie - z takich rzeczy, jak nasłuchiwanie zdarzeń, limity czasu itd. Zobacz poprzednie wideo (naprawdę).
https://developers.google.com/web/fundamentals/performance/rendering/
źródło
Tak, jest synchroniczny, bo to działa (śmiało, wpisz to w konsoli):
Powodem, dla którego widzisz alert, zanim zobaczysz zmianę strony, jest to, że renderowanie przeglądarki zajmuje więcej czasu i nie jest tak szybkie, jak wykonywanie javascript wiersz po wierszu.
źródło
text
w moim przykładzie) To odpowie na twoje pytanie, czy jest synchroniczny. Renderowanie przeglądarki a wykonanie JavaScript to jabłko i pomarańcze :)Plik
innerHTML
Własność rzeczywista jest aktualizowane synchronicznie, ale wizualne przerysem że zmiana ta powoduje dzieje asynchronicznie.Wizualne renderowanie DOM jest asynchroniczne w Chrome i nie nastąpi, dopóki bieżący stos funkcji JavaScript nie zostanie wyczyszczony, a przeglądarka nie będzie mogła zaakceptować nowego zdarzenia. Inne przeglądarki mogą używać oddzielnych wątków do obsługi kodu JavaScript i renderowania przeglądarki lub mogą pozwolić niektórym zdarzeniom uzyskać priorytet, podczas gdy alert wstrzymuje wykonanie innego zdarzenia.
Możesz to zobaczyć na dwa sposoby:
Jeśli dodasz
for(var i=0; i<1000000; i++) { }
przed alertem, dałeś przeglądarce dużo czasu na wykonanie przerysowania, ale tak się nie stało, ponieważ stos funkcji nie został wyczyszczony (add
nadal działa).Jeśli opóźnisz
alert
za pomocą asynchronicznegosetTimeout(function() { alert('random'); }, 1)
, proces przerysowania będzie kontynuowany przed funkcją opóźnioną przez setTimeout.0
, prawdopodobnie dlatego, że Chrome nadaje priorytet kolejce zdarzeń0
przekroczeniu limitu czasu przed jakimikolwiek innymi zdarzeniami (lub przynajmniej przed zdarzeniami przerysowania).źródło
setTimeout(func, 1)
nie działa za każdym razem sprawdzić ten film: youtu.be/r8caVE_a5KQ