JavaScript-Seiten-Lebenszyklusereignisse
Lerne die JavaScript-Lebenszyklusereignisse DOMContentLoaded, load, beforeunload und unload kennen — wann sie ausgelöst werden und welche modernen Alternativen empfohlen werden.
Jede Seite, die ein Browser öffnet, durchläuft eine vorhersehbare Abfolge von Phasen: Das HTML wird geparst, externe Ressourcen werden heruntergeladen, der Benutzer interagiert, und schließlich wird die Seite abgebaut. JavaScript stellt diese Abfolge über vier Seiten-Lebenszyklusereignisse bereit — DOMContentLoaded, load, beforeunload und unload. Wenn du genau weißt, wann jedes davon ausgelöst wird, kannst du Setup-Code zum frühestmöglichen sicheren Zeitpunkt ausführen, aufwendige Arbeit verzögern, bis alles bereit ist, und den Benutzer vor dem Verlust ungespeicherter Daten schützen.
Dieser Leitfaden erläutert, was jedes Ereignis bedeutet, in welcher Reihenfolge sie ausgelöst werden, typische Fallstricke und die modernen Ersatzmöglichkeiten für die Ereignisse, die Browser nun nicht mehr empfehlen. Jedes Beispiel unten ist ausführbar — füge es in eine HTML-Datei ein oder öffne es im eingebetteten Editor.
Der Seiten-Lebenszyklus auf einen Blick
Die Ereignisse werden in einer festen Reihenfolge ausgelöst. Die ersten beiden geschehen, wenn die Seite zum Leben erwacht; die letzten beiden, wenn der Benutzer die Seite verlässt:
| Ereignis | Ziel | Wann es ausgelöst wird | Typischer Einsatz |
|---|---|---|---|
DOMContentLoaded | document | HTML vollständig geparst; Scripts ausgeführt; Bilder/Styles können noch laden | UI initialisieren, Listener anhängen, DOM abfragen |
load | window | Die Seite und alle Unterressourcen (Bilder, Stylesheets, iframes) sind fertig | Bildgrößen auslesen, Code ausführen, der alles benötigt |
beforeunload | window | Der Benutzer ist dabei, die Seite zu verlassen | Vor ungespeicherten Änderungen warnen |
unload | window | Die Seite wird abgebaut (veraltet) | Legacy-Bereinigung / Analytics |
Eine wichtige Erkenntnis: DOMContentLoaded ist das Ereignis, das du meistens verwenden möchtest. Es wird weit früher ausgelöst als load, sodass das Anhängen deines Codes daran die Seite früher interaktiv macht.
Tiefer Einblick in das DOMContentLoaded-Ereignis
Das DOMContentLoaded-Ereignis wird ausgelöst, sobald das HTML-Dokument vollständig geparst wurde, was in der Regel lange vor dem Laden von Bildern, Stylesheets und anderen externen Ressourcen geschieht. Zu diesem Zeitpunkt ist der DOM-Baum vollständig, sodass document.getElementById, querySelector und ähnliche Methoden jedes im HTML enthaltene Element finden.
Da es nicht auf Bilder oder CSS wartet, solltest du DOMContentLoaded verwenden, wenn dein Script nur die DOM-Struktur benötigt — was der bei weitem häufigste Fall ist.
Wie Scripts DOMContentLoaded beeinflussen
Der Browser hält das Parsen des HTML an, wenn er auf ein gewöhnliches <script>-Tag trifft, führt das Script aus und fährt dann erst fort. Das bedeutet, dass DOMContentLoaded auf synchrone Scripts wartet. Es gibt zwei wichtige Nuancen:
<script async>wird ausgeführt, sobald es heruntergeladen ist, und blockiertDOMContentLoadednicht.<script defer>wird nach dem Parsen des Dokuments, aber vor dem Auslösen vonDOMContentLoadedausgeführt, in Dokumentreihenfolge.
Wenn du das Script-Timing mit diesen Attributen steuerst, findest du das vollständige Bild unter scripts: async, defer.
Den Zustand mit document.readyState prüfen
Wenn dein Code möglicherweise nach dem Parsen des DOM ausgeführt wird (z. B. ein dynamisch hinzugefügtes Script), würde der Listener nie ausgelöst, da das Ereignis bereits eingetreten ist. Schütze dich davor mit document.readyState:
function onReady() {
console.log('DOM is ready, current state:', document.readyState);
}
if (document.readyState === 'loading') {
// Still parsing — wait for the event.
document.addEventListener('DOMContentLoaded', onReady);
} else {
// 'interactive' or 'complete' — DOM is already ready.
onReady();
}readyState durchläuft drei Werte: "loading" während des Parsens, "interactive" sobald der DOM bereit ist (zu diesem Zeitpunkt wird DOMContentLoaded ausgelöst), und "complete" sobald alles einschließlich der Ressourcen geladen ist (zu diesem Zeitpunkt wird load ausgelöst).
Interaktives Beispiel: DOMContentLoaded in Aktion
Um DOMContentLoaded in Aktion zu sehen, aktualisiert das folgende Beispiel den Inhalt eines div-Elements, sobald das HTML-Dokument vollständig geparst wurde, aber bevor die gesamte Seite vollständig geladen ist.
<!DOCTYPE html>
<html lang="en">
<head>
<title>DOMContentLoaded Example</title>
</head>
<body>
<div id="output">Waiting for DOM...</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('output').innerHTML = 'DOM fully loaded and parsed!'
});
</script>
</body>
</html>Dieses Beispiel kann in eine beliebige HTML-Datei eingefügt und in einem Browser betrachtet werden, um zu beobachten, wie schnell DOMContentLoaded im Vergleich zum vollständigen Seitenlade vorgang ausgelöst wird.
Das load-Ereignis erkunden
Das load-Ereignis ist für Operationen unverzichtbar, bei denen die gesamte Webseite vollständig geladen sein muss, einschließlich aller abhängigen Ressourcen wie Bilder und Stylesheets. Wenn load ausgelöst wird, hat jedes Bild seine tatsächlichen Abmessungen, Schriftarten sind angewendet und iframes sind geladen — daher ist dies der richtige Ort für Code, der die gerenderte Seite misst.
Der Kompromiss liegt beim Timing: Ein einziges großes Bild oder ein langsames Drittanbieter-Widget verzögert load für die gesamte Seite. Deshalb solltest du load nur für Aufgaben reservieren, die wirklich von Ressourcen abhängen, und die gewöhnliche Initialisierung bei DOMContentLoaded belassen. Für das Laden und die Fehlerbehandlung einzelner Ressourcen (anstatt der gesamten Seite) siehe resource loading: onload and onerror.
Interaktives Beispiel: Das load-Ereignis demonstrieren
Hier erstellen wir ein Beispiel, bei dem eine Meldung erst angezeigt wird, nachdem alles auf der Seite vollständig geladen wurde. Wie du sehen kannst, findet das DOMContentLoaded-Ereignis immer vor dem load-Ereignis statt.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Load Event Example</title>
</head>
<body>
<div>You see first triggered event on top of the other.</div>
<script>
window.addEventListener('load', function() {
const newDiv = document.createElement("div");
newDiv.innerHTML = 'loaded event happened!'
document.body.append(newDiv);
});
window.addEventListener('DOMContentLoaded', function() {
const newDiv = document.createElement("div");
newDiv.innerHTML = 'DOMContentLoaded event happened!'
document.body.append(newDiv);
});
</script>
</body>
</html>Kopiere und teste diesen Code in deiner eigenen HTML-Umgebung, um den Timing-Unterschied zwischen DOMContentLoaded und load zu sehen.
Das beforeunload-Ereignis handhaben
Das beforeunload-Ereignis ist unglaublich nützlich, um Datenverlust zu verhindern und Benutzer zu warnen, bevor sie eine Seite verlassen, die möglicherweise ungespeicherte Änderungen enthält. Wenn ein Handler event.returnValue setzt, zeigt der Browser einen generischen Bestätigungsdialog an („Seite verlassen? Vorgenommene Änderungen werden möglicherweise nicht gespeichert").
Ein paar Regeln, die Browser jetzt durchsetzen und die du kennen solltest, bevor du dich darauf verlässt:
- Die benutzerdefinierte Nachricht wird ignoriert. Um Spam zu verhindern, zeigen Browser ihren eigenen Text an, unabhängig von dem String, den du zuweist. Es genügt,
returnValueauf einen beliebigen nicht leeren Wert zu setzen (oderevent.preventDefault()aufzurufen), um die Eingabeaufforderung auszulösen. - Der Dialog erscheint nur, wenn der Benutzer mit der Seite interagiert hat (geklickt, getippt usw.). Eine Seite, die der Benutzer nie berührt hat, kann die Navigation nicht blockieren.
- Registriere den Handler nur, wenn tatsächlich ungespeicherte Änderungen vorliegen, und entferne ihn, sobald die Daten gespeichert wurden. Ein permanenter
beforeunload-Handler nervt Benutzer und kann die Leistung des Back/Forward-Cache beeinträchtigen.
Ein robusteres Muster fügt den Listener basierend auf einem Dirty-Flag hinzu und entfernt ihn wieder:
let isDirty = false;
function beforeUnloadHandler(event) {
event.preventDefault();
// Required for some browsers to show the dialog.
event.returnValue = '';
}
function markDirty() {
if (!isDirty) {
isDirty = true;
window.addEventListener('beforeunload', beforeUnloadHandler);
}
}
function markSaved() {
isDirty = false;
window.removeEventListener('beforeunload', beforeUnloadHandler);
}Interaktives Beispiel: beforeunload-Bestätigung implementieren
Dieses Beispiel zeigt dem Benutzer einen Bestätigungsdialog an, wenn er versucht, die Seite zu verlassen, und hilft so, versehentlichen Datenverlust zu verhindern.
<!DOCTYPE html>
<html lang="en">
<head>
<title>beforeunload Example</title>
</head>
<body>
<p>Now if you want to exit this page, a confirmation alert will be shown as a result of the <code>beforeunload</code> event.</p>
<script>
window.addEventListener('beforeunload', function(event) {
event.returnValue = '';
});
</script>
</body>
</html>Teste diesen Code, indem du die „Selbst ausprobieren"-Seite aufrufst und dann versuchst, zu einer anderen Seite zu navigieren.
Das unload-Ereignis nutzen
Das unload-Ereignis ist veraltet und kann in den meisten modernen Browsern nicht mehr verwendet werden. Es gilt außerdem als schlechte Praxis. Dieser Abschnitt dient daher nur zur besseren Information über Legacy-Code.
Obwohl es aufgrund moderner Browser-Einschränkungen und des Aufkommens von Single-Page-Anwendungen weniger häufig verwendet wird, lief das unload-Ereignis historisch gesehen, wenn eine Seite abgebaut wurde — nützlich zum Bereinigen von Ressourcen oder zum Senden eines abschließenden Analytics-Pings. Das Problem ist, dass unload (und beforeunload) den Browser daran hindern, die Seite im Back/Forward-Cache (bfcache) zu speichern, was die Navigation mit der Zurück-Schaltfläche für alle verlangsamt.
Moderne Alternativen: visibilitychange und pagehide
Anstelle von unload solltest du auf visibilitychange hören und den Übergang zu "hidden" als den letzten zuverlässigen Moment zum Speichern des Zustands behandeln. Dies wird konsistent auf Desktop und Mobilgeräten ausgelöst, auch wenn der Benutzer Tabs wechselt oder die App schließt:
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
// Last reliable point to save state.
console.log('Page hidden — flush analytics / save draft here');
}
});Zum Senden von Daten beim Verlassen der Seite verwende navigator.sendBeacon(), das eine Anfrage in die Warteschlange stellt, die auch nach dem Schließen der Seite noch ausgeführt wird:
function sendStats(data) {
navigator.sendBeacon('/log', JSON.stringify(data));
}Interaktives Beispiel: Das unload-Ereignis verwenden
Dieser Code zeigt eine Alert-Meldung an, wenn die Seite entladen wird. Wie erwähnt ist er veraltet und funktioniert in den meisten modernen Browsern nicht — bevorzuge stattdessen visibilitychange wie oben beschrieben.
<!DOCTYPE html>
<html lang="en">
<head>
<title>unload Example</title>
</head>
<body>
<script>
window.addEventListener('unload', function(event) {
alert('Page is unloading...');
// Perform cleanup tasks or analytics here
});
</script>
</body>
</html>Fazit
Jedes dieser Ereignisse dient einer bestimmten Phase im Lebenszyklus einer Webseite, vom ersten Laden bis zum abschließenden Entladen. Die praktischen Empfehlungen sind kurz:
- Führe die meiste Initialisierung bei
DOMContentLoadedaus — es wird am frühesten ausgelöst und der DOM ist bereit. - Verwende
loadnur, wenn du darauf angewiesen bist, dass Bilder, Schriftarten oder andere Unterressourcen vollständig vorhanden sind. - Verwende
beforeunload, um ungespeicherte Änderungen zu schützen, und füge den Listener nur hinzu, wenn Daten noch nicht gespeichert sind. - Vermeide
unload; greife stattdessen aufvisibilitychangeundnavigator.sendBeacon()zurück.
Um tiefer einzutauchen, erkunde diese verwandten Kapitel:
- Introduction to browser events
- Scripts: async, defer
- Resource loading: onload and onerror
- Browser environment and specs