Signatur
Beschreibung
Die schreibgeschützte Eigenschaft window.performance gibt das Performance-Objekt des aktuellen Browsing-Kontexts zurück. Es ist der Einstiegspunkt für die High Resolution Time API, die User Timing API (mark(), measure()) sowie die Performance Timeline mit Navigations-, Ressourcen- und Paint-Einträgen.
Du verwendest performance, wenn du genaue Laufzeiten von Code messen willst. Anders als Date.now() liefert performance.now() einen monotonen Zeitstempel in Millisekunden mit Nachkommastellen, gemessen ab performance.timeOrigin (in der Regel der Beginn der Navigation). Dieser Wert ist unabhängig von Änderungen an der Systemuhr und eignet sich deshalb für Benchmarks, Animationen und Monitoring.
Wichtige Mitglieder des zurückgegebenen Objekts:
now()– aktueller hochauflösender Zeitstempel relativ zutimeOrigintimeOrigin– absoluter Startzeitpunkt (Unix-Epoche in ms)mark(name)/measure(name, start, end)– eigene Messpunkte und ZeitspannengetEntries(),getEntriesByType(type),getEntriesByName(name)– Einträge der Performance Timeline abfragenclearMarks(),clearMeasures(),clearResourceTimings()– Puffer leerentoJSON()– serialisierbare Darstellung
Für die laufende Beobachtung neuer Einträge (etwa Largest Contentful Paint oder Long Tasks) ist PerformanceObserver besser geeignet als wiederholtes Abfragen mit getEntries().
Rückgabewert
Performance-Objekt des aktuellen Fensters. Die Eigenschaft ist schreibgeschützt; innerhalb eines Fensters wird immer dasselbe Objekt zurückgegeben.Beispiele
Laufzeit einer Funktion messen
const sortiereGrosseListe = () => {
const daten = Array.from({ length: 200_000 }, () => Math.random());
return daten.sort((a, b) => a - b);
};
const start = performance.now();
sortiereGrosseListe();
const dauer = performance.now() - start;
console.log(`Sortieren dauerte ${dauer.toFixed(2)} ms`);
User Timing: Marken und Messungen für einen API-Aufruf
const ladeBenutzer = async () => {
performance.mark('fetch-start');
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const benutzer = await response.json();
performance.mark('fetch-ende');
const messung = performance.measure('benutzer-laden', 'fetch-start', 'fetch-ende');
console.log(`${benutzer.length} Benutzer in ${Math.round(messung.duration)} ms geladen`);
// Aufräumen, damit der Puffer nicht wächst
performance.clearMarks();
performance.clearMeasures();
};
ladeBenutzer();
Navigations- und Ressourcen-Timings auswerten
window.addEventListener('load', () => {
const [nav] = performance.getEntriesByType('navigation');
console.log('TTFB:', Math.round(nav.responseStart - nav.requestStart), 'ms');
console.log('DOMContentLoaded:', Math.round(nav.domContentLoadedEventEnd), 'ms');
const langsam = performance
.getEntriesByType('resource')
.filter((r) => r.duration > 200)
.map((r) => `${r.name} (${Math.round(r.duration)} ms)`);
console.log('Langsame Ressourcen:', langsam);
});
Neue Einträge mit PerformanceObserver beobachten
const observer = new PerformanceObserver((liste) => {
for (const eintrag of liste.getEntries()) {
console.log('LCP:', Math.round(eintrag.startTime), 'ms', eintrag.element);
}
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
// Absolute Zeit eines relativen Zeitstempels berechnen
const absolut = new Date(performance.timeOrigin + performance.now());
console.log(absolut.toISOString());
// Wichtig · Fallstricke
- Reduzierte Genauigkeit: Zum Schutz vor Timing-Angriffen (Spectre) runden Browser
performance.now()ab, typischerweise auf 5 µs bis 100 µs, in Firefox mitprivacy.resistFingerprintingsogar auf 100 ms. Eine feinere Auflösung gibt es nur in cross-origin-isolierten Seiten (HeaderCross-Origin-Opener-PolicyundCross-Origin-Embedder-Policy). - Relativ statt absolut:
performance.now()zählt abtimeOrigin, nicht ab der Unix-Epoche. Zeitstempel aus verschiedenen Fenstern oder Workern kannst du nur übertimeOriginvergleichen. - Veraltete APIs:
performance.timingundperformance.navigationsind veraltet. Verwende stattdessenperformance.getEntriesByType('navigation')(PerformanceNavigationTiming). - Pufferlimits: Der Puffer für Ressourcen-Timings ist standardmäßig auf etwa 250 Einträge begrenzt. Mit
performance.setResourceTimingBufferSize()kannst du ihn vergrößern oder mitclearResourceTimings()leeren. Ruf nach vielenmark()-AufrufenclearMarks()auf, damit kein Speicherleck entsteht. - Cross-Origin-Ressourcen: Bei fremden Ressourcen sind detaillierte Timings (z. B. DNS- oder Verbindungsdauer) nur dann verfügbar, wenn der Server den Header
Timing-Allow-Originsendet. Andernfalls stehen dort0-Werte. - Kompatibilität:
now(),mark()undmeasure()werden von allen modernen Browsern unterstützt. Optionen wiemeasure(name, { start, end, detail })gibt es erst seit etwa 2020/2021. In Web Workern erreichst du das Objekt überself.performance, in Node.js über das globaleperformanceoderrequire('node:perf_hooks'). - Rechne bei Benchmarks mit Schwankungen durch JIT-Aufwärmphase, Garbage Collection und gedrosselte Hintergrund-Tabs. Miss deshalb mehrfach und bilde den Median.