Mastering Front-End Performance: How to Use PerformanceObserver & Metrics
This article explains how to monitor and analyze front‑end performance using the deprecated performance.timing API and the modern PerformanceObserver, detailing key web‑vital metrics such as TTFB, FCP, LCP, FID, and CLS, with code examples and practical interpretation guidelines.
Web technologies are widely used across iOS, Android, PC, Mac, Linux and other platforms, making performance monitoring essential to identify bottlenecks and optimize page speed.
performance.timing
performance.timing returns a PerformanceTiming object containing read‑only millisecond timestamps for each stage of page loading. const timing = performance.timing; connectEnd
connectStart
domComplete
secureConnectionStart
unloadEventEnd
unloadEventStart
By chaining these timestamps you can compute common performance metrics.
Examples of metric calculations:
White screen time
const general = timing.domComplete - timing.navigationStart;Redirect time
const redirect = timing.fetchStart - timing.navigationStart;DNS lookup time
const dns = timing.domainLookupEnd - timing.domainLookupStart;TCP connection time
const connect_tcp = timing.connectEnd - timing.connectStart;Request time
const request = timing.responseStart - timing.requestStart;Response download time
const response = timing.responseEnd - timing.responseStart;Asset download time
const assets = timing.domComplete - timing.responseEnd;Note: performance.timing is deprecated.
Deprecated: This feature is no longer recommended. Some browsers still support it, but it may be removed from the web standard.
It only measures network‑related data and cannot capture detailed user‑interaction timings.
PerformanceObserver
PerformanceObserver can listen to PerformanceEntry events such as marks, measures, paints, largest‑contentful‑paint, etc.
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(`name: ${entry.name}, type: ${entry.entryType}, start: ${entry.startTime}, duration: ${entry.duration}`);
});
});
observer.observe({ entryTypes: ["mark", "measure"] });
performance.mark("registered-observer");Browser output example:
name: registered-observer, type: mark, start: 4254.199999999255, duration: 0
name: routeChange, type: mark, start: 6358.5999999996275, duration: 0
name: beforeRender, type: mark, start: 6406, duration: 0
name: Next.js-route-change-to-render, type: measure, start: 6358.5999999996275, duration: 47.40000000037253
name: afterRender, type: mark, start: 6409.0999999996275, duration: 0PerformanceEntry.entryTypes include:
element – reports element load time (string)
navigation – page URL (URL)
resource – resource URL (URL)
mark – name passed to performance.mark() (string)
measure – name passed to performance.measure() (string)
paint – "first-paint" or "first-contentful-paint"
longtask – reports long‑task instances (string)
TTFB
TTFB: Time to First Byte – time from request start to first byte received.
Collect TTFB with PerformanceObserver on navigation entries:
const observer = new PerformanceObserver((list) => {
const [pageNav] = list.getEntriesByType("navigation");
console.log(`TTFB: ${pageNav.responseStart}`);
});
observer.observe({ entryTypes: ["navigation"] });Good: < 800 ms; Poor: > 1800 ms.
FCP
FCP: First Contentful Paint – time until the first text or image is rendered.
Collect FCP with PerformanceObserver on "paint" entries:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const metricName = entry.name;
const time = Math.round(entry.startTime + entry.duration);
console.log(metricName, time);
}
});
observer.observe({ entryTypes: ["paint"] });Example output: first-paint 1139, first-contentful-paint 1139.
Excellent: < 1.8 s; Average: 1.8‑3 s; Poor: > 3 s.
LCP
LCP: Largest Contentful Paint – time when the largest visible element is rendered.
Collect LCP with PerformanceObserver on "largest-contentful-paint":
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log("LCP: ", entry.startTime);
}
});
observer.observe({ entryTypes: ["largest-contentful-paint"] });Example output: LCP: 99.099.
Excellent: < 2.5 s; Poor: > 4 s.
FID
FID: First Input Delay – latency between user interaction and browser response.
Collect FID with PerformanceObserver on "first-input":
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const time = entry.processingStart - entry.startTime;
console.log(entry.entryType, time);
}
});
observer.observe({ entryTypes: ["first-input"] });
function onClick() { console.log("click"); }Example output: first-input 4.2.
Target: < 100 ms.
CLS
CLS: Cumulative Layout Shift – measures visual stability of the page.
Calculate CLS using "layout-shift" entries:
let clsValue = 0;
let clsEntries = [];
let sessionValue = 0;
let sessionEntries = [];
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (!entry.hadRecentInput) {
const firstSessionEntry = sessionEntries[0];
const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
if (sessionValue && entry.startTime - lastSessionEntry.startTime < 1000 && entry.startTime - firstSessionEntry.startTime < 5000) {
sessionValue += entry.value;
sessionEntries.push(entry);
} else {
sessionValue = entry.value;
sessionEntries = [entry];
}
if (sessionValue > clsValue) {
clsValue = sessionValue;
clsEntries = sessionEntries;
console.log("CLS:", clsValue, clsEntries);
}
}
}
}).observe({ type: "layout-shift", buffered: true });
setTimeout(() => {
document.querySelector("div").style.marginTop = "25vh";
}, 1000);CLS < 0.1 is good; > 0.25 is poor.
Conclusion
The article demonstrates how to use the performance and PerformanceObserver APIs to monitor front‑end metrics such as server response, first paint, largest contentful paint, input delay, and layout shift, and explains how to interpret the values for optimization.
References: https://github.com/WICG/layout-instability
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
