Start · Sprachen · JavaScript · Referenz · PerformanceSoftNavigation

PerformanceSoftNavigation

Schnittstelle

Liefert Performance-Einträge vom Typ <code>"soft-navigation"</code> mit Timing-Daten zu clientseitigen Routenwechseln in Single-Page-Applications.

seit JavaScript Experimentell: nur Chromium (hinter Flag bzw. Orig Kategorie: webapi

Signatur

interface PerformanceSoftNavigation extends PerformanceEntry

Beschreibung

In einer klassischen Mehrseiten-Anwendung erzeugt jeder Seitenwechsel eine neue Dokument-Navigation, die über PerformanceNavigationTiming sowie Metriken wie LCP gemessen werden kann. Single-Page-Applications (React Router, Vue Router, Angular usw.) wechseln die Ansicht dagegen per JavaScript, ohne ein neues Dokument zu laden. Solche Soft-Navigationen waren für die Performance-APIs bisher nicht sichtbar. Deshalb galten Core Web Vitals in SPAs oft nur für den ersten Seitenaufruf.

PerformanceSoftNavigation schließt diese Lücke. Der Browser erkennt eine Soft-Navigation mithilfe einer Heuristik und erzeugt dann einen Performance-Eintrag mit dem entryType "soft-navigation". Die Heuristik besteht aus drei Bedingungen:

  • Der Nutzer löst eine Interaktion aus (z. B. click oder keydown).
  • Die URL ändert sich per History-API (history.pushState()/replaceState()) oder Navigation-API.
  • Das DOM wird sichtbar verändert und anschließend gezeichnet.

Die wichtigsten Eigenschaften (größtenteils von PerformanceEntry geerbt):

  • name: die neue URL nach der Soft-Navigation.
  • entryType: immer "soft-navigation".
  • startTime: Zeitstempel der auslösenden Nutzerinteraktion (in Millisekunden, bezogen auf performance.timeOrigin).
  • duration: Zeit von der Interaktion bis zum Abschluss der Navigation bzw. bis zum ersten relevanten Paint.
  • navigationId: eindeutige ID der Navigation. Andere Einträge wie LCP, Layout-Shift oder Event-Timing tragen dieselbe ID. So lassen sie sich einer bestimmten „virtuellen Seite“ zuordnen.

Weitere Felder wie interactionId oder Paint-Zeitstempel (paintTime, presentationTime) werden je nach Spezifikationsstand in Chromium ergänzt. Die Einträge liest man typischerweise mit einem PerformanceObserver aus und schickt sie an ein RUM-System (Real User Monitoring), um Ladezeiten pro Route zu messen.

Rückgabewert

Typ
PerformanceSoftNavigation
Beschreibung
Du erzeugst die Instanzen nicht selbst, es gibt keinen öffentlichen Konstruktor. Du erhältst sie über PerformanceObserver oder performance.getEntriesByType("soft-navigation").

Beispiele

Soft-Navigationen mit PerformanceObserver beobachten

// Prüfen, ob der Browser den Eintragstyp unterstützt
if (PerformanceObserver.supportedEntryTypes.includes('soft-navigation')) {
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      console.log(
        `Soft-Navigation zu ${entry.name}: ` +
        `Start ${entry.startTime.toFixed(0)} ms, ` +
        `Dauer ${entry.duration.toFixed(0)} ms, ID ${entry.navigationId}`
      );
    }
  });
  // buffered: true liefert auch bereits aufgetretene Einträge
  observer.observe({ type: 'soft-navigation', buffered: true });
} else {
  console.log('Soft-Navigation-Messung wird nicht unterstützt.');
}
Soft-Navigation zu https://shop.example/produkte/42: Start 5321 ms, Dauer 184 ms, ID 7f3c…

Soft-Navigation im SPA-Router auslösen

// Minimal-Router: Klick + pushState + DOM-Änderung erfüllen die Heuristik
document.querySelector('#link-kontakt').addEventListener('click', (event) => {
  event.preventDefault();
  history.pushState({}, '', '/kontakt');
  document.querySelector('main').innerHTML = '<h1>Kontakt</h1><p>Schreib uns!</p>';
});

// Später alle erfassten Soft-Navigationen abfragen
setTimeout(() => {
  const entries = performance.getEntriesByType('soft-navigation');
  console.log(entries.map((e) => e.name));
}, 2000);
["https://example.com/kontakt"]

LCP-Einträge einer Soft-Navigation zuordnen (RUM)

const routes = new Map(); // navigationId → { url, start, lcp }

new PerformanceObserver((list) => {
  for (const nav of list.getEntries()) {
    routes.set(nav.navigationId, { url: nav.name, start: nav.startTime, lcp: null });
  }
}).observe({ type: 'soft-navigation', buffered: true });

new PerformanceObserver((list) => {
  for (const lcp of list.getEntries()) {
    const route = routes.get(lcp.navigationId);
    if (route) {
      // LCP relativ zum Beginn der Soft-Navigation
      route.lcp = lcp.startTime - route.start;
    }
  }
}).observe({ type: 'largest-contentful-paint', buffered: true, includeSoftNavigationObservations: true });

// Beim Verlassen der Seite an den Server senden
addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    navigator.sendBeacon('/rum', JSON.stringify([...routes.values()]));
  }
});

// Wichtig · Fallstricke

Experimentell: Die API gibt es bislang nur in Chromium-basierten Browsern, und dort nur mit aktiviertem Flag (chrome://flags/#enable-experimental-web-platform-features bzw. „Soft Navigation Heuristics“) oder über einen Origin Trial. Firefox und Safari unterstützen sie nicht. Prüfe die Unterstützung immer mit PerformanceObserver.supportedEntryTypes.includes('soft-navigation').

  • Die Spezifikation (WICG „Soft Navigations“) ändert sich noch. Eigenschaftsnamen und Observer-Optionen wie includeSoftNavigationObservations können sich ändern oder wegfallen.
  • Die Erkennung beruht auf einer Heuristik. Programmatische URL-Wechsel ohne Nutzerinteraktion (z. B. Weiterleitungen per Timer) oder Wechsel ohne sichtbare DOM-Änderung werden nicht als Soft-Navigation erkannt.
  • Die Werte von startTime beziehen sich weiterhin auf den Ursprung des Dokuments (performance.timeOrigin). Für routenbezogene Metriken musst du den startTime der Soft-Navigation selbst abziehen.
  • Ohne buffered: true entgehen dir Einträge, die vor der Registrierung des Observers entstanden sind.