DEV Community

Victor Magarlamov
Victor Magarlamov

Posted on • Updated on

Performance measuring

Measure first and then optimize!
-- Golden rule

You can't optimize what you can't measure.
-- Another golden rule

There are many articles on how to improve performance in JavaScript applications. Of course, it’s good to know all these tricks and tips, but it’s much better to know what I will tell in this article 😇.

Three key performance features

  1. Navigation speed
  2. Resources loading speed
  3. Code execution speed

In general, web application performance depends on these characteristics — navigation, resources, and scripting. And together they are part of the Performance Timeline. Thanks to the Performance Web API, we can easily measure and read Performance Timeline metrics. Let's do it.

Navigation Timing

function getNavigationMetric () {
  const [entry] = performance.getEntriesByType("navigation");
  console.table(entry.toJSON());
}

The getEntriesByType method returns a list of the PerfomanceEntity objects, each of which is a part of the Performance Timeline. In this case, we get an object of type “navigation”. This type will be contained in the initiatorType property of the object, which we will see in the console after calling our function in the body.onload (or in the componentDidMount life cycle method in a React app).

Other interesting properties will be: responseEnd - time of the last byte received from the navigation request (startTime) and duration - equal to the difference between responseEnd and startTime, respectively.

Resource Timing

function getResourceMetric () {
  const entries = performance.getEntriesByType("resource");
  console.log(entries);
}

When we call this function in body.onload, we get PerfomanceEntity for all the resources that the page loads. If we filter these entries by initiatorType, we get metrics for images (initiatorType === “img”), scripts (initiatorType === “script”), etc.

User Timing

function getUserMetric () {
  performance.mark("do_something_start_mark");
  doSomething();
  performance.mark("do_something_end_mark");

  performance.measure("measure", "do_something_start_mark", "do_something_end_mark");

  const entries = performance.getEntriesByType("measure");
  console.log(entries);
}

In this case, we get the timeline metric from startMark to the endMark label. By the way, it’s good practice to delete the used metric using the performance.clearMeasures method.

PerfomanceObserver

Well, we have metrics, and now we can send them to the server for analysis. The best way to do this is to use the Performance Observer API.

const observer = new PerformanceObserver(list => {
  const res = list.getEntries().map(entry => ({
    name: entry.name,
    type: entry.entryType,
    start: entry.startTime,
    duration: entry.duration,
  }));

  sendMetrics(res);
});

observer.observe({entryTypes: ['resource', 'navigation', 'measure']});

More about the Perfomance Timeline API

Top comments (5)

Collapse
 
pavelloz profile image
Paweł Kowalski • Edited

The best way to do this is to use the Performance Observer API.

By accident i was writing almost exactly the same code today, but didnt see Observer API in MDN, why is it the best way to do it?

Collapse
 
victormagarlamov profile image
Victor Magarlamov

Because WebAPI's observers do they work in own thread, asynchronously.

Collapse
 
pavelloz profile image
Paweł Kowalski • Edited

Ouh, i just did setTimeout 100 and it worked out cool ;)

Collapse
 
jwp profile image
John Peters

Nice Victor thanks!

 const [entry] = performance.getEntriesByType("navigation");

Is performance a library?

Collapse
 
victormagarlamov profile image
Victor Magarlamov

Yes, I forgot to say it! Sorry! Performance is a property of the window object. developer.mozilla.org/en-US/docs/W...