Skip to content

Performance API

This lesson explains Performance API with clear examples, use cases, and best practices so you can use HTML5 APIs confidently in real web applications.

HTML5 Performance API Overview

The HTML5 Performance API allows developers to measure how fast a web page loads, how long JavaScript operations take, how resources perform, and how users experience page responsiveness. It provides high-resolution timing data through the performance object.

The Performance API is commonly used for page load monitoring, Core Web Vitals tracking, resource timing, custom performance marks, measuring API calls, debugging slow JavaScript, tracking user interactions, and building real-user monitoring dashboards.

Feature Description
API Name Performance API
Main Object window.performance
High-Resolution Timer performance.now()
Custom Marks performance.mark()
Custom Measures performance.measure()
Best Use Measure page load, resources, JavaScript, and user experience.

Basic Performance API Example

// HTML5 Performance API

const start =
  performance.now();

for (let i = 0; i < 1000000; i += 1) {
  // Simulate work
}

const end =
  performance.now();

console.log(
  "Task took " + (end - start) + " milliseconds"
);

The performance.now() method provides a precise timestamp in milliseconds, making it better than Date.now() for measuring code execution time.

Performance API Core Concepts

Concept Description Example Syntax
High Resolution Time Precise time measurement in milliseconds. performance.now()
Performance Entry A recorded timing entry for navigation, resource, mark, or measure. performance.getEntries()
Mark Custom named timestamp. performance.mark("start")
Measure Duration between two marks. performance.measure("load", "start", "end")
Observer Watches performance entries as they happen. new PerformanceObserver(callback)
Navigation Timing Measures document loading lifecycle. performance.getEntriesByType("navigation")

Performance API Methods

Method Description Example
performance.now() Returns current high-resolution timestamp. performance.now()
performance.mark() Creates a custom timestamp marker. performance.mark("app-start")
performance.measure() Measures duration between marks. performance.measure("render-time", "start", "end")
performance.getEntries() Returns all performance entries. performance.getEntries()
performance.getEntriesByType() Returns entries by type. performance.getEntriesByType("resource")
performance.getEntriesByName() Returns entries by name. performance.getEntriesByName("api-load")
performance.clearMarks() Clears custom marks. performance.clearMarks()
performance.clearMeasures() Clears custom measures. performance.clearMeasures()

Measure Code with Marks and Measures

// Measure custom app work

performance.mark("data-start");

const response =
  await fetch("/api/products");

const products =
  await response.json();

performance.mark("data-end");

performance.measure(
  "product-api-load",
  "data-start",
  "data-end"
);

const measure =
  performance.getEntriesByName(
    "product-api-load"
  )[0];

console.log(
  "API load time:",
  measure.duration
);

Marks and measures help track custom performance points such as API calls, rendering, hydration, search, filtering, checkout, and user actions.

Resource Timing Example

// Measure loaded resources

const resources =
  performance.getEntriesByType(
    "resource"
  );

resources.forEach((resource) => {
  console.log(
    resource.name,
    resource.duration
  );
});

Resource timing entries help identify slow images, scripts, stylesheets, fonts, API requests, and third-party assets.

Find Slow Resources

const slowResources =
  performance
    .getEntriesByType("resource")
    .filter((resource) => resource.duration > 1000);

slowResources.forEach((resource) => {
  console.log(
    "Slow resource:",
    resource.name,
    resource.duration
  );
});

This example finds resources that take more than one second to load. It is useful for debugging slow assets and third-party scripts.

PerformanceObserver Example

// Observe performance entries

const observer =
  new PerformanceObserver((list) => {
    list.getEntries()
      .forEach((entry) => {
        console.log(
          entry.entryType,
          entry.name,
          entry.duration
        );
      });
  });

observer.observe(
  {
    entryTypes: ["mark", "measure", "resource"]
  }
);

PerformanceObserver allows applications to receive performance entries as they are created instead of checking entries later.

Paint Timing Example

const paintEntries =
  performance.getEntriesByType(
    "paint"
  );

paintEntries.forEach((entry) => {
  console.log(
    entry.name,
    entry.startTime
  );
});

Paint timing entries can include values such as first-paint and first-contentful-paint, helping developers understand when users first see content.

Largest Contentful Paint Example

const lcpObserver =
  new PerformanceObserver((list) => {
    const entries =
      list.getEntries();

    const lastEntry =
      entries[entries.length - 1];

    console.log(
      "LCP:",
      lastEntry.startTime
    );
  });

lcpObserver.observe(
  {
    type: "largest-contentful-paint",
    buffered: true
  }
);

Largest Contentful Paint measures when the largest visible content element is rendered. It is commonly used as a user experience metric for page loading speed.

Cumulative Layout Shift Example

let cls = 0;

const clsObserver =
  new PerformanceObserver((list) => {
    list.getEntries()
      .forEach((entry) => {
        if (!entry.hadRecentInput) {
          cls += entry.value;
        }
      });

    console.log("CLS:", cls);
  });

clsObserver.observe(
  {
    type: "layout-shift",
    buffered: true
  }
);

Cumulative Layout Shift tracks unexpected layout movement. High CLS can make pages feel unstable and frustrating to use.

Long Task Detection Example

const longTaskObserver =
  new PerformanceObserver((list) => {
    list.getEntries()
      .forEach((entry) => {
        console.log(
          "Long task:",
          entry.duration
        );
      });
  });

longTaskObserver.observe(
  {
    type: "longtask",
    buffered: true
  }
);

Long task entries help detect JavaScript work that blocks the main thread and causes poor responsiveness.

Common Performance Entry Types

Entry Type Description Common Use
navigation Page navigation and document loading timing. Measure page load lifecycle.
resource Timing for loaded resources. Find slow scripts, images, fonts, APIs.
mark Custom timestamp. Measure app-specific checkpoints.
measure Duration between marks. Track feature or workflow timing.
paint First paint and first contentful paint. Measure visible page rendering.
largest-contentful-paint Largest visible content render time. Core Web Vitals loading metric.
layout-shift Unexpected visual layout movement. Measure visual stability.
longtask Main-thread tasks longer than 50ms. Detect UI blocking work.

Send Performance Metrics to Server

function sendMetric(name, value) {
  navigator.sendBeacon(
    "/analytics/performance",
    JSON.stringify(
      {
        name: name,
        value: value,
        page: location.pathname
      }
    )
  );
}

performance.mark("checkout-start");

// Checkout work happens here

performance.mark("checkout-end");

performance.measure(
  "checkout-duration",
  "checkout-start",
  "checkout-end"
);

const checkoutMeasure =
  performance.getEntriesByName(
    "checkout-duration"
  )[0];

sendMetric(
  checkoutMeasure.name,
  checkoutMeasure.duration
);

Sending metrics to a server helps teams monitor real-user performance across browsers, devices, locations, and network conditions.

performance.now() vs Date.now()

Feature performance.now() Date.now()
Precision High-resolution time. Lower precision timestamp.
Affected by System Clock No. Yes.
Best Use Performance measurement. Current date and time.
Returns Milliseconds since time origin. Milliseconds since Unix epoch.

Common Performance API Use Cases

  • Measure page load speed.
  • Track Core Web Vitals.
  • Measure API request duration.
  • Find slow JavaScript tasks.
  • Monitor image, script, font, and CSS load times.
  • Track checkout, search, and form workflow performance.
  • Build real-user monitoring dashboards.
  • Debug production performance issues.

Performance API Best Practices

  • Use performance.now() instead of Date.now() for timing code.
  • Use custom marks and measures for important app workflows.
  • Clear old marks and measures when no longer needed.
  • Use PerformanceObserver for live metrics.
  • Track both lab metrics and real-user metrics.
  • Monitor resources, long tasks, layout shifts, and paint timings.
  • Send only useful metrics to analytics to avoid noise.
  • Use performance data to guide optimization decisions.

Common Performance API Mistakes

  • Using Date.now() for precise performance measurement.
  • Creating many marks without clearing them.
  • Tracking metrics without acting on them.
  • Ignoring mobile and slow network users.
  • Measuring only page load and ignoring interactions.
  • Running expensive analytics code on the main thread.
  • Assuming lab performance equals real-user performance.
  • Not separating first-time visits from cached visits.

Performance API vs Observer APIs

API Measures Best Use
Performance API Timing, resource, navigation, paint, and custom metrics. Performance measurement and monitoring.
Intersection Observer Element visibility. Lazy loading, infinite scroll, analytics impressions.
Resize Observer Element size changes. Responsive components and layout monitoring.
Mutation Observer DOM changes. Dynamic content and DOM monitoring.

Key Takeaways

  • The Performance API measures browser and application performance.
  • performance.now() provides precise timing.
  • performance.mark() creates custom checkpoints.
  • performance.measure() calculates duration between marks.
  • PerformanceObserver watches performance entries as they occur.
  • Use performance data to improve real user experience, not just scores.

Pro Tip

Use the Performance API to measure business-critical flows such as search, checkout, login, dashboard loading, editor saving, and route transitions. Real optimization starts when you measure the exact user workflow that matters most.