Matthias Fulde: Eventhandling und Microtasks

Beitrag lesen

Hallo Michael,

ja, der Talk von Jake Archibald ist gut, aber er geht glaube ich an der Fragestellung von Rolf etwas vorbei, beziehungsweise erklärt nur einen Teil.

Nach meinem Verständnis ist es wiefolgt:

Wenn der Button in Rolfs Beispiel geklickt wird, bekommt der Browser vom Betriebssystem eine Nachricht und fügt daraufhin in der entsprechenden Taskqueue eine neue Task hinzu. (Hier ist zu beachten, dass es mehrere Taskqueues für verschiedene Arten von Tasks gibt, mit verschiedenen Prioritäten. Benutzerinteraktion hat typischerweise eine höhere Priorität als etwa Netzwerktasks, um die Seite responsiv zu halten.) Wenn dann alle früheren oder priorisierten Tasks und alle Microtasks abgearbeitet sind, kommt die Task für unser Event an die Reihe.

Der Algorithmus der nun abgearbeitet wird ist in Firing Events beschrieben. Wir erzeugen ein Eventobjekt und folgen dann Dispatching Events, also wie von Rolf beschrieben einmal runter im Baum zum Zielobjekt und dann wieder rauf. Für jedes Objekt auf dem Ereignispfad für das wir passende Eventlistener registriert haben, rufen wir die hinterlegten Funktionen auf. Das ist in der Spec der Algorithmus Invoke. Hier müssen wir der Spur der Brotkrumen folgen. Der für uns relevante Abschnitt ist call a user object's operation. Das führt unseren Handler aus.

Entscheidend für die Fragestellung ist dabei der letzte Schritt, das anschließende Aufräumen. Im Schritt clean up after running script heißt es nämlich:

„If the JavaScript execution context stack is now empty, perform a microtask checkpoint.“

Wenn einer unserer registrierten Eventhandler abgearbeitet wurde, ist der Callstack wieder leer, und an der Stelle ist ein Microtask Checkpoint vorgesehen. Wenn wir also wie im Beispiel von Rolf in den Eventhandlern Code ausführen, der Microtasks hinzufügt, dann werden die direkt nach der Rückgabe des jeweiligen Handlers ausgeführt, und bevor der nächste Handler aufgerufen wird. Das ist auch konsistent mit dem Beispiel aus Archibalds Talk.

Wenn wir aus dem Programmcode heraus ein Event starten, statt als Antwort auf eine Benutzeraktion, also zum Beispiel click auf einem Elementobjekt aufrufen, dann sieht das natürlich anders aus. In dem Fall existiert ja nach der Rückgabe der Handler noch ein Kontext auf dem Callstack, nämlich der, von dem aus wir die Methode aufgerufen haben. Entsprechend werden hier die Microtasks erst nach allen Eventhandlern und dem aufrufenden Code abgearbeitet.

Meines Wissens wird für die meisten Ereignisse eine Task hinzugefügt. Die kümmert sich dann wie oben beschrieben um die Ausführung der Handler, wobei eben zwischen jedem Aufruf Microtasks ausgeführt werden können. Die Layoutphase kommt danach.

Was oft untergeht und für Verwirrung sorgt, ist, dass der Eventloop letztlich Browsercode ist und sich nicht nur um JavaScript dreht. Viele Tasks haben mit JavaScript gar nichts zu tun. Folglich gibt es da auch nicht zwingend eine eins-zu-eins Beziehung zwischen Tasks und Callbacks. Eine Task kann auch mehrere Callbacks ausführen, wobei aufgrund der obigen Regel nach jeder Ausführung die hinterlegten Microtasks abgearbeitet werden.

Viele Grüße,

Matthias