Signatur
Beschreibung
Die Eigenschaft signal eines NavigateEvent liefert ein AbortSignal, das an die aktuelle Navigation gebunden ist. Es wird abgebrochen (aborted === true), wenn die Navigation nicht mehr fortgesetzt werden soll, z. B. weil der Nutzer im Browser auf „Stopp“ klickt, eine andere Navigation startet (neuer Link-Klick, navigation.navigate(), Zurück-Taste) oder window.stop() aufgerufen wird.
Gedacht ist das Signal vor allem für Single-Page-Anwendungen, die Navigationen mit event.intercept() abfangen und im handler asynchron Daten laden. Reicht man event.signal an fetch() oder andere abbrechbare APIs weiter, werden veraltete Anfragen automatisch abgebrochen und es entstehen keine Wettlaufsituationen, bei denen eine langsame alte Antwort die neue Seite überschreibt.
Zusätzlich kann man mit signal.addEventListener("abort", …) oder signal.throwIfAborted() eigene Aufräumarbeiten erledigen, etwa Ladeanzeigen ausblenden, Animationen stoppen oder lange Berechnungsschleifen beenden. Über signal.reason lässt sich der Grund des Abbruchs (in der Regel eine DOMException mit Namen "AbortError") auslesen.
Rückgabewert
AbortSignal, das abgebrochen wird, sobald die zugehörige Navigation abgebrochen wird. Die Eigenschaft ist schreibgeschützt.Beispiele
Signal an fetch() im Intercept-Handler weitergeben
navigation.addEventListener("navigate", (event) => {
if (!event.canIntercept || event.hashChange || event.downloadRequest) return;
const url = new URL(event.destination.url);
if (!url.pathname.startsWith("/artikel/")) return;
event.intercept({
async handler() {
// Bricht die Anfrage automatisch ab, wenn der Nutzer weiternavigiert
const response = await fetch(`/api${url.pathname}`, {
signal: event.signal,
});
const artikel = await response.json();
document.querySelector("main").textContent = artikel.titel;
},
});
});
Aufräumen beim Abbruch über das abort-Ereignis
navigation.addEventListener("navigate", (event) => {
if (!event.canIntercept) return;
const spinner = document.querySelector("#lade-anzeige");
event.intercept({
async handler() {
spinner.hidden = false;
event.signal.addEventListener("abort", () => {
spinner.hidden = true;
console.log("Navigation abgebrochen:", event.signal.reason?.name);
}, { once: true });
await new Promise((resolve) => setTimeout(resolve, 3000));
spinner.hidden = true;
},
});
});
// Klickt der Nutzer während der 3 Sekunden auf „Stopp“:
Lange Verarbeitung mit throwIfAborted() abbrechen
const renderListe = async (eintraege, signal) => {
const liste = document.querySelector("#liste");
liste.replaceChildren();
for (const eintrag of eintraege) {
signal.throwIfAborted(); // wirft AbortError, falls abgebrochen
const li = document.createElement("li");
li.textContent = eintrag;
liste.append(li);
await new Promise(requestAnimationFrame); // UI nicht blockieren
}
};
navigation.addEventListener("navigate", (event) => {
if (!event.canIntercept) return;
event.intercept({
handler: async () => {
const daten = Array.from({ length: 500 }, (_, i) => `Eintrag ${i + 1}`);
try {
await renderListe(daten, event.signal);
} catch (err) {
if (err.name === "AbortError") console.log("Rendern gestoppt");
else throw err;
}
},
});
});
// Wichtig · Fallstricke
- Browser-Kompatibilität: Die Navigation API ist lange nur in Chromium-Browsern (Chrome, Edge, Opera ab Version 102) verfügbar gewesen; in Firefox und Safari kam sie erst später hinzu. Vorher per
if ("navigation" in window)prüfen und einen Fallback (z. B. History API) vorsehen. - Das Signal wird nur für die jeweilige Navigation ausgelöst. Nach erfolgreichem Abschluss wird es nicht abgebrochen – ein
abort-Listener läuft also nur bei echtem Abbruch. - Wird ein Handler abgebrochen und reicht man das Signal an
fetch()weiter, verwirft der Browser das Promise mit einemAbortError. Wer den Fehler abfängt, sollteAbortErrorvon echten Netzwerkfehlern unterscheiden und nicht als Fehlermeldung anzeigen. - Ohne
event.intercept()ist das Signal kaum nützlich, da die Navigation dann ohnehin normal (mit Seitenwechsel) abläuft. - Soll bei Abbruch zusätzlich ein Zeitlimit gelten, lassen sich Signale mit
AbortSignal.any([event.signal, AbortSignal.timeout(5000)])kombinieren (neuere Browser).