PerformanceObserver streams timeline entries as they are recorded, replacing polling of performance.getEntries(). Pass entryTypes, or one type with buffered: true to get earlier entries too; PerformanceObserver.supportedEntryTypes lists 15 in Chrome 152 1 .
<h1>Quarterly report</h1>
<script>
new PerformanceObserver((list) => list.getEntries().forEach((e) => console.log(e.entryType,
e.name || e.element.localName, Math.round(e.startTime), Math.round(e.duration))))
.observe({ entryTypes: ['largest-contentful-paint', 'mark', 'measure'] });
performance.mark('build-start');
for (let i = 0, sum = 0; i < 3e7; i++) sum += i; // slow work
performance.measure('build-report', 'build-start');
</script>mark build-start 359 0 measure build-report 359 35 largest-contentful-paint h1 424 0
The blocking loop pushed LCP back. The old performance.timing is deprecated in favor of the navigation entry; Core Web Vitals covers Web Vitals.