Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62
Subscribe to my email list now at http://jauyeung.net/subscribe/
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.