Rolf B: <button> in <p>: obj.parentElement is null

Beitrag lesen

problematische Seite

Hallo Linuchs,

das ist alles pseudoparallel. Natürlich, wenn Du einen Ajax-Request machst, läuft der am Server parallel zu deinem Script ab. Aber innerhalb des JavaScript ist alles sequenziell. Und es gibt sogenannte Webworker, die echt parallel zum JavaScript-Hauptthread laufen können, aber die musst Du dann auch asynchron über Messaging ansprechen. Das passiert hier nicht.

Das entscheidende Vehikel in JavaScript sind die Makro- und Mikrotaskqueue. DOM Events und setTimeout erzeugen Einträge in der Makrotaskqueue, bestimmte andere Vorgänge (wie Promises) erzeugen Einträge in der Mikrotaskqueue.

Pro Eintrag in der Makrotaskqueue ruft die JS Engine den entsprechenden Handler auf. Folge dieses Handlers können neue Einträge in Mikro- und Makrotaskqueue sein. Dann endet der Handler. Und erst jetzt schaut JavaScript nach weiteren Tasks. Zuerst die Mikrotasks, und erst wenn es davon keine mehr gibt, guckt es nach neuen Makrotasks.

Was du hast, sind zwei Handler für ein click Event. Das click-Event wird vom Browser in die Makrotask-Queue gestellt. Irgendwann beschließt JavaScript, diesen Makrotask abzuarbeiten, und ruft dafür nacheinander die registrierten Handler auf. In welcher Reihenfolge die laufen, ist auch nicht ganz trivial, da gibt's ja die Capture-Phase, und die Bubbling-Phase. Du hast keinen capture-Handler registriert, und da onclick ein Attribut ist, wird dieser Handler unweigerlich der erste registrierte sein, alle anderen kommen später.

Deswegen passiert folgendes:

  • click wird auf dem Button ausgelöst
  • makrotask wird in die queue gestellt
  • makrotask beginnt
  • ein Click-Event wird erstellt und die Elternkette des Button gebildet
  • Capture-Phase: das Click-Event wird allen Elementen der Elternkette vom Root bis zum Button. Hat eins davon einen capture-Handler, kommt der jetzt zum Zuge (Netscape-Modell in den Browserkriegen).
  • Bubble-Phase: Das Click-Event wird allen Elementen der Elternkette vom Button bis zum Root präsentiert. Hat eins davon einen bubble-Handler (das ist der Default, das ist bei Dir der Fall), wird er nun aufgerufen.

Interessant ist: Das click-Event bleibt das gleiche. Egal was die Handler am DOM herummachen. Und das event.target im Click-Event bleibt erhalten, egal ob es noch im DOM steht oder nicht.

Und weil setCookie ein bubble-Handler am Button ist, und dein addEventListener Handler ein bubble-Handler am Body, kommt setCookie zuerst dran. Es nimmt den Button aus dem DOM, wodurch sein parentElement auf null gesetzt wird.

Und der nächste Handler ist angeschmiert.

Rolf

--
sumpsi - posui - obstruxi