Categories
JavaScript APIs

Measuring JavaScript App Performance with the Performance API

Spread the love

With the JavaScript Performance API, we have an easy way to measure the performance of a front-end JavaScript apps.

In this article, we’ll look at how to use it to measure our app’s performance.

Performance

We can measure the performance of an app with a few methods. The Performance API provides a precise and consistent definition of time. The API will gives us with a high precision timestamp to mark the time when a piece of code starts running and finishes.

The timestamp is in milliseconds and it should be accurate to 5 microseconds. The browser can represent the value as time in milliseconds accurate to a millisecond if there’re hardware or software constraints that make our browser unable to provide value with the higher accuracy.

We can use it as in the following example:

const startTime = performance.now();
for (let i = 0; i <= 10000; i++) {
  console.log(i);
}
const endTime = performance.now();
console.log(endTime - startTime)

In the code above, we used the performance object to mark the time when the loop starts running and finishes running.

Then we logged the time by subtracting endTime by startTime to give us the elapsed time when the loop ran in milliseconds.

Serializing the Performance object

The performance object is serialized by the toJSON method.

We can use it as follows:

const js = window.performance.toJSON();
console.log(JSON.stringify(js));

Then we get something like:

{"timeOrigin":1579540433373.9158,"timing":{"navigationStart":1579540433373,"unloadEventStart":1579540433688,"unloadEventEnd":1579540433688,"redirectStart":0,"redirectEnd":0,"fetchStart":1579540433374,"domainLookupStart":1579540433376,"domainLookupEnd":1579540433423,"connectStart":1579540433423,"connectEnd":1579540433586,"secureConnectionStart":1579540433504,"requestStart":1579540433586,"responseStart":1579540433678,"responseEnd":1579540433679,"domLoading":1579540433691,"domInteractive":1579540433715,"domContentLoadedEventStart":1579540433715,"domContentLoadedEventEnd":1579540433716,"domComplete":1579540433716,"loadEventStart":1579540433716,"loadEventEnd":0},"navigation":{"type":0,"redirectCount":0}}

logged.

Measuring Multiple Actions

We can use the mark method to mark our actions and the use the measure method to measure the time between actions by passing in the names.

For example, we can measure time with markings as follows:

performance.mark('beginLoop');
for (let i = 0; i < 10000; i++) {
  console.log(i);
}
performance.mark('endLoop');
performance.measure('measureLoop', 'beginLoop', 'endLoop');
console.log(performance.getEntriesByName('measureLoop'));

In the code above, we called the mark method before the loop starts and after the loop ends.

Then we call the measure method with a name we create to get the time difference later and both markers so that we can get the time from them and get the time difference.

Then we called performance.getEntriesByName(‘measureLoop’) to get the computed duration with the duration property of the returned object.

‘measureLoop’ is the name we made up to get the time difference by name, and ‘beginLoop' and 'endLoop' are our time markers.

We can get entries marked by the mark method with the getEntriesByType method. It takes a string for the type. To do this, we can write:

performance.mark('beginLoop');
for (let i = 0; i < 10000; i++) {
  console.log(i);
}
performance.mark('endLoop');
performance.measure('measureLoop', 'beginLoop', 'endLoop');
console.log(performance.getEntriesByType("mark"))

Then the console.log should get us the following:

[
  {
    "name": "beginLoop",
    "entryType": "mark",
    "startTime": 133.55500000761822,
    "duration": 0
  },
  {
    "name": "endLoop",
    "entryType": "mark",
    "startTime": 1106.3149999827147,
    "duration": 0
  }
]

There’s also a getEntriesByName method which takes the name and the type as the first and second arguments respectively.

For example, we can write:

performance.mark('beginLoop');
for (let i = 0; i < 10000; i++) {
  console.log(i);
}
performance.mark('endLoop');
performance.measure('measureLoop', 'beginLoop', 'endLoop');
console.log(performance.getEntriesByName('beginLoop', "mark"));

Then we get:

[
  {
    "name": "beginLoop",
    "entryType": "mark",
    "startTime": 137.6299999828916,
    "duration": 0
  }
]

from the console.log .

We can also use getEntries by passing in an object with the name and entryType properties as follows:

performance.mark('beginLoop');
for (let i = 0; i < 10000; i++) {
  console.log(i);
}
performance.mark('endLoop');
performance.measure('measureLoop', 'beginLoop', 'endLoop');
console.log(performance.getEntries({
  name: "beginLoop",
  entryType: "mark"
}));

Then we get something like:

[
  {
    "name": "[https://fiddle.jshell.net/_display/](https://fiddle.jshell.net/_display/)",
    "entryType": "navigation",
    "startTime": 0,
    "duration": 0,
    "initiatorType": "navigation",
    "nextHopProtocol": "h2",
    "workerStart": 0,
    "redirectStart": 0,
    "redirectEnd": 0,
    "fetchStart": 0.2849999873433262,
    "domainLookupStart": 0.2849999873433262,
    "domainLookupEnd": 0.2849999873433262,
    "connectStart": 0.2849999873433262,
    "connectEnd": 0.2849999873433262,
    "secureConnectionStart": 0.2849999873433262,
    "requestStart": 2.3250000085681677,
    "responseStart": 86.29499998642132,
    "responseEnd": 94.03999999631196,
    "transferSize": 1486,
    "encodedBodySize": 752,
    "decodedBodySize": 1480,
    "serverTiming": [],
    "unloadEventStart": 101.23999998904765,
    "unloadEventEnd": 101.23999998904765,
    "domInteractive": 126.96500000311062,
    "domContentLoadedEventStart": 126.9800000009127,
    "domContentLoadedEventEnd": 127.21500001498498,
    "domComplete": 128.21500000427477,
    "loadEventStart": 128.2249999931082,
    "loadEventEnd": 0,
    "type": "navigate",
    "redirectCount": 0
  },
  {
    "name": "[https://fiddle.jshell.net/js/lib/dummy.js](https://fiddle.jshell.net/js/lib/dummy.js)",
    "entryType": "resource",
    "startTime": 115.49500000546686,
    "duration": 0,
    "initiatorType": "script",
    "nextHopProtocol": "h2",
    "workerStart": 0,
    "redirectStart": 0,
    "redirectEnd": 0,
    "fetchStart": 115.49500000546686,
    "domainLookupStart": 115.49500000546686,
    "domainLookupEnd": 115.49500000546686,
    "connectStart": 115.49500000546686,
    "connectEnd": 115.49500000546686,
    "secureConnectionStart": 0,
    "requestStart": 115.49500000546686,
    "responseStart": 115.49500000546686,
    "responseEnd": 115.49500000546686,
    "transferSize": 0,
    "encodedBodySize": 0,
    "decodedBodySize": 0,
    "serverTiming": []
  },
  {
    "name": "[https://fiddle.jshell.net/css/result-light.css](https://fiddle.jshell.net/css/result-light.css)",
    "entryType": "resource",
    "startTime": 115.77999999281019,
    "duration": 0,
    "initiatorType": "link",
    "nextHopProtocol": "h2",
    "workerStart": 0,
    "redirectStart": 0,
    "redirectEnd": 0,
    "fetchStart": 115.77999999281019,
    "domainLookupStart": 115.77999999281019,
    "domainLookupEnd": 115.77999999281019,
    "connectStart": 115.77999999281019,
    "connectEnd": 115.77999999281019,
    "secureConnectionStart": 0,
    "requestStart": 115.77999999281019,
    "responseStart": 115.77999999281019,
    "responseEnd": 115.77999999281019,
    "transferSize": 0,
    "encodedBodySize": 49,
    "decodedBodySize": 29,
    "serverTiming": []
  },
  {
    "name": "beginLoop",
    "entryType": "mark",
    "startTime": 128.3699999912642,
    "duration": 0
  },
  {
    "name": "measureLoop",
    "entryType": "measure",
    "startTime": 128.3699999912642,
    "duration": 887.0650000171736
  },
  {
    "name": "endLoop",
    "entryType": "mark",
    "startTime": 1015.4350000084378,
    "duration": 0
  }
]

from the console.log .

With markers, we can name our time markers, so we can measure multiple actions.

Clearing Actions

We can clear performance markers by calling the clearMarks method. For example, we can do that as follows:

performance.mark("dog");
performance.mark("dog");
performance.clearMarks('dog');

There’s also a clearMeasures method to clear measurements and clearResourceTimings to clear performance entries.

For example, we can use it as follows:

performance.mark('beginLoop');
for (let i = 0; i < 10000; i++) {
  console.log(i);
}
performance.mark('endLoop');
performance.measure('measureLoop', 'beginLoop', 'endLoop');
performance.clearMeasures("measureLoop");
console.log(performance.getEntriesByName('measureLoop'));

Then we should see an empty array when we call getEntriesByName .

To remove all performance entries, we can use the clearResourceTimings method. It clears the performance data buffer and sets the performance data buffer to zero.

It takes no arguments and we can use it as follows:

performance.mark('beginLoop');
for (let i = 0; i < 10000; i++) {
  console.log(i);
}
performance.mark('endLoop');
performance.measure('measureLoop', 'beginLoop', 'endLoop');
performance.clearResourceTimings();

In the code above, we called the clearResourceTimings method to reset the buffers and performance data to zero so that we can run our performance tests with a clean slate.

Conclusion

We can use the Performance API to measure the performance of a piece of front-end JavaScript code.

To do this, we can use the now method to get the timestamp and then find the difference between the 2.

We can also use the mark method to mark the time and then use the measure method to compute the measurement.

There’re also various ways to get the performance entries and clear the data.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *