Measure first and then optimize!
-- Golden ruleYou 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
- Navigation speed
- Resources loading speed
- 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']});
Top comments (5)
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?
Because WebAPI's observers do they work in own thread, asynchronously.
Ouh, i just did setTimeout 100 and it worked out cool ;)
Nice Victor thanks!
Is performance a library?
Yes, I forgot to say it! Sorry! Performance is a property of the window object. developer.mozilla.org/en-US/docs/W...