Ist innerHTML asynchron?

101

Ich hoffe, ich mache mich nicht zum Narren, aber ich versuche zu verstehen, was in diesen beiden Codezeilen passiert:

document.body.innerHTML = 'something';
alert('something else');

Was ich beobachte, ist, dass eine Warnung angezeigt wird, bevor HTML aktualisiert wurde (oder vielleicht, aber die Seite wurde nicht aktualisiert / neu gestrichen / was auch immer)

Überprüfen Sie diesen Codepen, um zu sehen, was ich meine.

Bitte beachten Sie, dass auch Putting alertin setTimeout(..., 0)nicht hilft. Es sieht so aus, als ob mehr Ereignisschleifen erforderlich sind innerHTML, um die Seite tatsächlich zu aktualisieren.

BEARBEITEN:

Ich habe vergessen zu erwähnen, dass ich Chrome verwende, und habe andere Browser nicht überprüft. Sieht so aus, als wäre es nur in Chrome sichtbar. Trotzdem interessiert mich immer noch, warum das passiert.

pro Stück Bart
quelle
4
Dies ist typisch für Chrome.
Trincot
2
@ Trincot danke! Ich habe vergessen zu erwähnen, dass ich Chrome verwende, und habe vor der Frage keinen anderen Browser ausprobiert. Haben Sie eine Referenz?
pro Stück Bart
16
Das Ändern des DOM ist synchron. Das Rendern des DOM erfolgt tatsächlich, nachdem der JavaScript-Stapel gelöscht wurde. developer.google.com/web/fundamentals/performance/rendering JavaScript> Stil> Layout> Farbe> Verbund. (Zumindest für Chrome. Andere Browser sind ähnlich.)
Jered
2
Nur eine Vermutung: Das Blockieren von Alarmen verhindert, dass der Browser einen Repaint-Schritt erreicht. Während sich das DOM geändert hat, durfte es noch nicht neu gestrichen werden. wieder nur eine Vermutung.
zzzzBov
2
@qbolec überprüfen Sie dieses Video: youtu.be/r8caVE_a5KQ
apieceofbart

Antworten:

130

Das Festlegen von innerHTML ist synchron, ebenso wie die meisten Änderungen, die Sie am DOM vornehmen können. Das Rendern der Webseite ist jedoch eine andere Geschichte.

(Denken Sie daran, DOM steht für "Document Object Model". Es ist nur ein "Modell", eine Darstellung von Daten. Der Benutzer sieht auf seinem Bildschirm ein Bild davon, wie dieses Modell aussehen sollte. Das Ändern des Modells erfolgt also nicht sofort Ändern Sie das Bild - die Aktualisierung dauert einige Zeit.)

Das Ausführen von JavaScript und das Rendern der Webseite erfolgt separat. Um es vereinfachend, zuerst alle JavaScript auf der Seite ausgeführt wird (von der Ereignisschleife - schauen Sie sich dieses hervorragende Video für weitere Details) und dann nach , dass der Browser auf die Webseite alle Änderungen macht für den Benutzer zu sehen. Aus diesem Grund ist das "Blockieren" eine so große Sache - das Ausführen von rechenintensivem Code verhindert, dass der Browser den Schritt "JS ausführen" übergeht und in den Schritt "Seite rendern" übergeht, wodurch die Seite einfriert oder stottert.

Die Pipeline von Chrome sieht folgendermaßen aus:

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können, geschieht das gesamte JavaScript zuerst. Dann wird die Seite gestylt, angelegt, gemalt und zusammengesetzt - das "Rendern". Nicht die gesamte Pipeline führt jeden Frame aus. Dies hängt davon ab, welche Seitenelemente gegebenenfalls geändert wurden und wie sie erneut gerendert werden müssen.

Hinweis: alert()Ist auch synchron und wird während des JavaScript-Schritts ausgeführt. Aus diesem Grund wird das Warndialogfeld angezeigt, bevor Sie Änderungen an der Webseite sehen.

Sie könnten jetzt fragen: "Moment mal, was genau wird in diesem 'JavaScript'-Schritt in der Pipeline ausgeführt? Wird mein gesamter Code 60 Mal pro Sekunde ausgeführt?" Die Antwort lautet "Nein" und geht zurück auf die Funktionsweise der JS-Ereignisschleife. JS-Code wird nur ausgeführt, wenn er sich im Stapel befindet - von Ereignissen wie Ereignis-Listenern, Zeitüberschreitungen usw. Siehe vorheriges Video (wirklich).

https://developers.google.com/web/fundamentals/performance/rendering/

scherzte
quelle
1
Danke für die Antwort. Ich kannte einige Details zur Ereignisschleife usw. Diese Pipeline ist absolut sinnvoll, aber wie Beispiele zeigen, ist sie nicht in jedem Browser gleich. Wenn andere Browser warten, bis die Seite neu gezeichnet wurde, bevor eine Warnung angezeigt wird, kann dies zu einer großen Verzögerung zwischen dem Klicken auf die Schaltfläche und der Anzeige der Warnung selbst führen. Ich werde später versuchen, damit zu spielen.
pro Stück Bart
@apieceofbart Andere Browser können die Seite auch einfach asynchron neu zeichnen, während sie das Javascript-Material anhalten, bis der Benutzer das Warnfenster bearbeitet. Das bedeutet nicht, dass sie warten müssen, bis das Repaint erfolgt.
Jonas Schäfer
27

Ja, es ist synchron, da dies funktioniert (geben Sie es in Ihre Konsole ein):

document.body.innerHTML = 'text';
alert(document.body.innerHTML);// you will see a 'text' alert

Der Grund, warum Sie die Warnung sehen, bevor sich die Seite ändert, ist, dass das Rendern des Browsers mehr Zeit in Anspruch nimmt und nicht so schnell ist, wie Ihr Javascript zeilenweise ausgeführt wird.

d -_- b
quelle
Danke, das habe ich überprüft. Aber es muss etwas Spezifisches für Chrome sein - es funktioniert wie erwartet in anderen Browsern. Oder ist es vielleicht ihr Fehler, dass sie darauf warten, dass die Seite neu gestrichen wird, um zur nächsten Zeile von Javascript zu gelangen?
pro Stück Bart
3
Zeigt die Warnung den richtigen Text an? ( textin meinem Beispiel) Damit wird Ihre Frage beantwortet, ob es synchron ist. Browser-Rendering vs. Javascript-Ausführung ist Apfel und Orangen :)
d -_- b
Es hat aber nichts mit der Frage zu tun
pro Stück Bart
1
Ihre Frage lautet wörtlich "Ist innerHTML asynchron?". Wenn der Wert unmittelbar nach der Synchronisation verwendet werden kann, nein? Ich denke, Sie wollen mehr über das Rendern von Seiten fragen, nicht über die synchrone Qualität von innerHTML.
d -_- b
8
Ja, die Frage war eindeutig falsch, aber ich wusste nicht, was ich fragen sollte. Wenn ich den richtigen gekannt hätte, hätte ich wahrscheinlich die Antwort gefunden. Ich wollte nicht gemein sein, danke für die Antwort!
pro Stück Bart
6

Die innerHTMLeigentliche Eigenschaft wird zwar synchron aktualisiert, das durch diese Änderung verursachte visuelle Neuzeichnen erfolgt jedoch asynchron.

Das visuelle Rendern des DOM ist in Chrome asynchron und erfolgt erst, nachdem der aktuelle JavaScript-Funktionsstapel gelöscht wurde und der Browser ein neues Ereignis akzeptieren kann. Andere Browser verwenden möglicherweise separate Threads, um JavaScript-Code und das Rendern von Browsern zu verarbeiten, oder sie lassen einige Ereignisse Priorität erhalten, während eine Warnung die Ausführung eines anderen Ereignisses stoppt.

Sie können dies auf zwei Arten sehen:

  1. Wenn Sie for(var i=0; i<1000000; i++) { }vor Ihrer Warnung hinzufügen , haben Sie dem Browser genügend Zeit zum erneuten Zeichnen gegeben, dies ist jedoch nicht der Fall, da der Funktionsstapel nicht gelöscht wurde ( addnoch ausgeführt wird).

  2. Wenn Sie Ihre alertasynchrone Verzögerung setTimeout(function() { alert('random'); }, 1)verzögern, kann der Neuzeichnungsprozess die durch setTimeout verzögerte Funktion ausführen.

    • Dies funktioniert nicht, wenn Sie eine Zeitüberschreitung von verwenden 0, möglicherweise weil Chrome 0Zeitüberschreitungen vor anderen Ereignissen (oder zumindest vor Neuzeichnungsereignissen) Priorität in der Ereigniswarteschlange einräumt .
Apsiller
quelle
Danke für die Antwort! Bitte nicht, dass auch setTimeout(func, 1)nicht jedes Mal funktioniert hat, überprüfen Sie dieses Video: youtu.be/r8caVE_a5KQ
apieceofbart