Profiling Web Performance in Browser Dev Tools

Jesse Barkdoll
Updated: May 7, 2024 Published: March 25, 2024

Overview of the Performance Panel in Chromium-based Browsers

The performance tab gives us the ability to record and capture information about the performance when loading or running a page in the browser. We developers can use this in a variety of ways to diganose performance issues related to our apps, find expensive operations that are slowing our sites down, and get an overall picture of what improvements might benefit our front ends to give users a smoother experience.

Here are some example scenarios where you may want to use the Performance panel to diagnose an issue:

At first glance, there seems to be a lot going on within it, but it’s not as bad as it looks! The entire performance panel is organized into a series of horizontal tracks. We can parse through the tracks to focus on specific points of time in a recording.

Here are the different areas of the panel:

Header Bar

header bar

The header bar of the panel contains:

Timeline Track

timeline track

The very first track shows an overall graph of the activity during a recording. We can use the handles or simply click and drag to select a segment of the timeline to analyze it in more detail.

You can use the W, A, S, D keys to navigate the performance panel timeline.

Frames Track

frames track

Shows frames of the screen when something changes and the browser renders an update. You can find where frames drop and look into the surrounding factors to determine what is causing the performance to suffer.

Animations Track

animation track

For viewing simple analytics data related to animations performed on the page.

Main Track

main track

Displays activity that happens on the main thread. This is the central track and will likely be the track you spend the most time reviewing for typical use cases.

Bottom Panel

bottom panel

At the bottom (by default), you will see a few tabs that give you in-depth detail on whichever part of the recording you are currently analyzing.

An Example with RxJS

If you are interested in trying this out yourself, I have published an example project on GitHub using Vite and RxJS.

preview of example project Here we use RxJS observables to test multiple elements being updated by the browser every 1 millisecond.[1]

Here is the click event handler that is set up to trigger a rapid update of counter values for all 12 counter elements (marked with class "counter")

main.js
import { Subject, interval, takeUntil } from 'rxjs';

export const setUpPerfTest = (elm, counters) => {
  elm.innerHTML = 'Start';

  // 'Start' handler
  elm.addEventListener('click', () => {
    elm.innerHTML = 'Stop';
    const stop$ = new Subject();

    // Update all counters every 1 time unit (usually milliseconds)
    interval(1)
      .pipe(takeUntil(stop$))
      .subscribe(
        val => counters.forEach(
          ctr => ctr.innerHTML = val
        )
      );

    // 'Stop' handler
    elm.addEventListener('click', () => {
      stop$.next();

      // Reset 'Start' handler
      setUpPerfTest(elm, counters);

    }, { once: true });
  }, { once: true });
}

Recording a Profile

To record a profile, click record, activate page code to make the browser perform computations, and then stop the recording.

Analyzing a DOM Event

Below, we can see a small amount of information on our click event (Pointer event) and its timings when locating it on the Interactions track.

bottom panel summary tab

For more in-depth information, we can zoom into where activity picks up on the main thread (by using the Main track) and we locate the click handler function, which is defined anonymously in our main.js code above. We are able to see it under the label “(anonymous)”.

In Bottom Panel > Bottom Up or Bottom Panel > Event Log, we can see the entire call stack’s function cascade of how we get from Click event to our own code. Bottom up will show you from the top of the stack all the way to the origin of the execution cascade.

The Summary tab shows us information on the specific call like its total runtime, a distribution chart of the runtime between load time, self runtime, and runtime of child function calls.

bottom panel summary tab

Closing Thoughts

Although there is no specific performance bottleneck we need to diagnose here, I hope this overview of how the performance panel can prove useful for devs who need more insights on troubleshooting front end performance and render issues apps.

Footnotes