Breaking Down the Performance API

Avatar of Preethi
Preethi on

JavaScript’s Performance API is prudent, because it hands over tools to accurately measure the performance of Web pages, which, in spite of being performed since long before, never really became easy or precise enough.

That said, it isn’t as easy to get started with the API as it is to actually use it. Although I’ve seen extensions of it covered here and there in other posts, the big picture that ties everything together is hard to find.

One look at any document explaining the global performance interface (the access point for the Performance API) and you’ll be bombarded with a slew of other specifications, including High Resolution Time API, Performance Timeline API and the Navigation API among what feels like many, many others. It’s enough to make the overarching concept more than a little confusing as to what exactly the API is measuring but, more importantly, make it easy to overlook the specific goodies that we get with it.

Here’s an illustration of how all these pieces fit together. This can be super confusing, so having a visual can help clarify what we’re talking about.

The Performance API includes the Performance Timeline API and, together, they constitute a wide range of methods that fetch useful metrics on Web page performance.

Let’s dig in, shall we?

High Resolution Time API

The performance interface is a part of the High Resolution Time API.

“What is High Resolution Time?” you might ask. That’s a key concept we can’t overlook.

A time based on the Date is accurate to the millisecond. A high resolution time, on the other hand, is precise up to fractions of milliseconds. That’s pretty darn precise, making it more ideal for yielding accurate measurements of time.

It’s worth pointing out that a high resolution time measured by User Agent (UA) doesn’t change with any changes in system time because it is taken from a global, increasingly monotonic clock created by the UA. The time always increases and cannot be forced to reduce. That becomes a useful constraint for time measurement.

Every time measurement measured in the Performance API is a high resolution time. Not only does that make it a super precise way to measure performance but it’s also what makes the API a part of the High Resolution Time API and why we see the two often mentioned together.

Performance Timeline API

The Performance Timeline API is an extension of the Performance API. That means that where the Performance API is part of the High Resolution Time API, the Performance Timeline API is part of the Performance API.

Or, to put it more succinctly:

High Resolution Time API
└── Performance API
    └── Performance Timeline API

Performance Timeline API gives us access to almost all of the measurements and values we can possibly get from whole of the Performance API itself. That’s a lot of information at our fingertips with a single API and why the diagram at the start of this article shows them nearly on the same plane as one another.

There are many extensions of the Performance API. Each one returns performance-related entries and all of them can be accessed and even filtered through Performance Timeline, making this a must-learn API for anyone who wants to get started with performance measurements. They are so closely related and complementary that it makes sense to be familiar with both.

The following are three methods of the Performance Timeline API that are included in the performance interface:

  • getEntries()
  • getEntriesByName()
  • getEntriesByType()

Each method returns a list of (optionally filtered) performance entries gathered from all of the other extensions of the Performance API and we’ll get more acquainted with them as we go.

Another key interface included in the API is PerformanceObserver. It watches for a new entry in a given list of performance entries, and notifies of the same. Pretty handy for real-time monitoring!

The Performance Entries

The things we measure with the Performance API are referred to as “entries” and they all offer a lot of insight into Web performance.

Curious what they are? MDN has a full list that will likely get updated as new items are released, but this is what we currently have:

Entry What it Measures Parent API
frame Measures frames, which represent a loop of the amount of work a browser needs to do to process things like DOM events, resizing, scrolling and CSS animations. Frame Timing API
mark Creates a timestamp in the performance timeline that provides values for a name, start time and duration. User Timing API
measure Similar to mark in that they are points on the timeline, but they are named for you and placed between marks. Basically, they’re a midpoint between marks with no custom name value. User Timing API
navigation Provides context for the load operation, such as the types of events that occur. Navigation Timing API
paint Reports moments when pixels are rendered on the screen, such as the first paint, first paint with content, the start time and total duration. Paint Timing API
resource Measures the latency of dependencies for rendering the screen, like images, scripts and stylesheets. This is where caching makes a difference! Resource Timing API

Let’s look at a few examples that illustrate how each API looks in use. To learn more in depth about them, you can check out the specifications linked up in the table above. The Frame Timing API is still in the works.

Paint Timing API, conveniently, has already been covered thoroughly on CSS-Tricks, but here’s an example of pulling the timestamp for when painting begins:

// Time when the page began to render 
console.log(performance.getEntriesByType('paint')[0].startTime)

The User Timing API can measure the performance for developer scripts. For example, say you have code that validates an uploaded file. We can measure how long that takes to execute:

// Time to console-print "hello"
// We could also make use of "performance.measure()" to measure the time
// instead of calculating the difference between the marks in the last line.
performance.mark('')
console.log('hello')
performance.mark('')
var marks = performance.getEntriesByType('mark')
console.info(`Time took to say hello ${marks[1].startTime - marks[0].startTime}`)

The Navigation Timing API shows metrics for loading the current page, metrics even from when the unloading of the previous page took place. We can measure with a ton of precision for exactly how long a current page takes to load:

// Time to complete DOM content loaded event
var navEntry = performance.getEntriesByType('navigation')[0]
console.log(navEntry.domContentLoadedEventEnd - navEntry.domContentLoadedEventStart)

The Resource Timing API is similar to Navigation Timing API in that it measures load times, except it measures all the metrics for loading the requested resources of a current page, rather than the current page itself. For instance, we can measure how long it takes an image hosted on another server, such as a CDN, to load on the page:

// Response time of resources
performance.getEntriesByType('resource').forEach((r) => {
console.log(`response time for ${r.name}: ${r.responseEnd - r.responseStart}`);
});

The Navigation Anomaly

Wanna hear an interesting tidbit about the Navigation Timing API?

It was conceived before the Performance Timeline API. That’s why, although you can access some navigation metrics using the Performance Timeline API (by filtering the navigation entry type), the Navigation Timing API itself has two interfaces that are directly extended from the Performance API:

  • performance.timing
  • performance.navigation

All the metrics provided by performance.navigation can be provided by navigation entries of the Performance Timeline API. As for the metrics you fetch from performance.timing, however, only some are accessible from the Performance Timeline API.

As a result, we use performance.timing to get the navigation metrics for the current page instead of using the Performance Timeline API via performance.getEntriesByType("navigation"):

// Time from start of navigation to the current page to the end of its load event
addEventListener('load', () => {
	with(performance.timing) 
		console.log(navigationStart - loadEventEnd);
})

Let’s Wrap This Up

I’d say your best bet for getting started with the Performance API is to begin by familiarizing yourself with all the performance entry types and their attributes. This will get you quickly acquainted with the end results of all the APIs—and the power this API provides for measuring performance.

As a second course of action, get to know how the Performance Timeline API probes into all those available metrics. As we covered, the two are closely related and the interplay between the two can open up interesting and helpful methods of measurement.

At that point, you can make a move toward mastering the fine art of putting the other extended APIs to use. That’s where everything comes together and you finally get see the full picture of how all of these APIs, methods and entries are interconnected.