Signatur
Beschreibung
stop() beendet die Stichprobenaufzeichnung eines Profilers, der mit new Profiler(options) gestartet wurde. Der Rückgabewert ist ein Promise, das mit einem ProfilerTrace-Objekt erfüllt wird. Darin steht, welche JavaScript-Funktionen während der Aufzeichnung auf dem Aufrufstapel lagen.
Die Methode gehört zur JS Self-Profiling API. Mit ihr kannst du die Leistung deines Codes direkt beim Nutzer messen, also in echten Sitzungen und nicht nur in den DevTools. Typische Einsätze: langsame Interaktionen analysieren, Startzeiten messen oder Profile gezielt an einen Analyse-Server schicken.
Das Profil ist platzsparend normalisiert und besteht aus vier Arrays:
resources: Skript-URLsframes: Funktionsname,resourceId,line,columnstacks:frameIdundparentId, bilden zusammen einen Baumsamples:timestampundstackId
Um einen vollständigen Aufrufstapel zu erhalten, gehst du von stackId aus über die parentId-Kette nach oben.
Nach stop() ist die Profiler-Instanz verbraucht. Für eine neue Messung erzeugst du einen neuen Profiler. Die Eigenschaft stopped zeigt an, ob der Profiler schon beendet wurde.
Rückgabewert
ProfilerTrace-Objekt ({ resources, frames, stacks, samples }) erfüllt wird. Es wird mit einer InvalidStateError-DOMException abgelehnt, wenn der Profiler bereits gestoppt war.Beispiele
Einfache Messung einer rechenintensiven Funktion
const fib = (n) => (n < 2 ? n : fib(n - 1) + fib(n - 2));
const profileFib = async () => {
const profiler = new Profiler({ sampleInterval: 10, maxBufferSize: 10_000 });
fib(30);
const trace = await profiler.stop();
console.log(`Samples: ${trace.samples.length}, Frames: ${trace.frames.length}`);
};
profileFib();
Profil einer Nutzerinteraktion an den Server senden
const button = document.querySelector('#export');
button.addEventListener('click', async () => {
if (!('Profiler' in window)) return exportData();
const profiler = new Profiler({ sampleInterval: 10, maxBufferSize: 5_000 });
try {
await exportData(); // die zu messende Arbeit
} finally {
const trace = await profiler.stop();
navigator.sendBeacon('/api/profiles', JSON.stringify(trace));
}
});
async function exportData() {
const rows = Array.from({ length: 200_000 }, (_, i) => `${i};${Math.random()}`);
return rows.join('\n');
}
Häufigste Funktionen aus dem Trace ermitteln
const topFunctions = (trace, limit = 5) => {
const counts = new Map();
for (const { stackId } of trace.samples) {
if (stackId === undefined) continue; // Leerlauf-Sample
const { frameId } = trace.stacks[stackId];
const name = trace.frames[frameId].name || '(anonym)';
counts.set(name, (counts.get(name) ?? 0) + 1);
}
return [...counts].sort((a, b) => b[1] - a[1]).slice(0, limit);
};
const run = async () => {
const profiler = new Profiler({ sampleInterval: 10, maxBufferSize: 10_000 });
const data = Array.from({ length: 1e6 }, () => Math.random());
data.sort((a, b) => a - b);
const trace = await profiler.stop();
console.table(topFunctions(trace));
};
run();
Doppeltes Stoppen abfangen
const profiler = new Profiler({ sampleInterval: 10, maxBufferSize: 1_000 });
await profiler.stop();
console.log(profiler.stopped);
try {
await profiler.stop();
} catch (err) {
console.log(err.name);
}
// Wichtig · Fallstricke
- Header erforderlich: Das HTML-Dokument muss mit dem HTTP-Header
Document-Policy: js-profilingausgeliefert werden. Fehlt der Header, wirft schonnew Profiler()einenNotAllowedError. - Kompatibilität: Die API ist experimentell und nur in Chromium-Browsern verfügbar. Vorher immer mit
'Profiler' in windowprüfen. - Nur einmal stoppen: Ein zweiter Aufruf von
stop()lehnt das Promise mitInvalidStateErrorab. Eine Instanz kann nicht neu gestartet werden. - Puffergrenze: Ist
maxBufferSizeerreicht, wird das Ereignissamplebufferfullausgelöst und es kommen keine weiteren Samples hinzu. In diesem Fall solltest dustop()zeitnah aufrufen, um die bisherigen Daten zu sichern. - Genauigkeit: Das tatsächliche Intervall zwischen den Samples kann größer sein als
sampleInterval, denn der Browser rundet auf seine eigene Mindestauflösung (oft 10 ms, unter Windows z. B. 16 ms). Sehr kurze Code-Abschnitte erscheinen deshalb eventuell gar nicht im Profil. - Datenschutz und Leistung: Frames aus fremden Skripten ohne CORS-Freigabe werden weggelassen. Profiling kostet selbst etwas Leistung. Zeichne deshalb in Produktion nur bei einem kleinen Teil der Nutzer auf (Sampling).