📜 ⬆️ ⬇️

User Timing API

This is a translation by Alex Danilo’s article about the User Timing API published on January 21, 2014.

High performance of web applications is crucial to achieve a good user experience. While web applications are becoming more complex, an understanding of the impact of productivity is vital to creating a competitive user experience. Over the past few years, various APIs have appeared in browsers to analyze network performance, load time, etc., but they do not provide the necessary information with sufficient flexibility to find problems that slow down an application. Using the User Timing API provides a mechanism to determine which part of your application is the slowest. This article will show you how to work with the User Timing API and examples of its use.

You cannot optimize what you cannot measure.

The first step in speeding up a web application is to understand where time losses occur. Measuring the time spent on the execution of individual parts of the Javascript code is an ideal way to determine hot spots, and this is the first step in understanding how to improve performance. Fortunately, the User Timing API provides a way to embed API calls in different parts of the code and then obtain detailed information about the execution time.
')
High Resolution time and 'now ()'

Accuracy is the basis of accurate time measurement There was no time to be content with millisecond accuracy of measurement, but the development of a site capable of being rendered at a speed of 60 FPS means that each frame must be rendered within 16 ms. That is, millisecond accuracy is not enough for a qualitative analysis. Thus, High Resolution Time was introduced, a new type of time measurement built into modern browsers. High Resolution Time provides timestamps in floating-point format, which allows measurements to be made to the microsecond level — a thousand times better than before.
To get the current time in the web application, call the ' now () ' method, extending the Performance interface:

var myTime = window.performance.now(); 

There is another interface, PerformanceTiming , which provides additional information on how the application is loaded. The 'now ()' method returns the time elapsed since the navigationStart event occurred in PerformanceTiming.

Type DOMHighResTimeStamp

When trying to profile web applications in the past, you would most likely have to deal with something like Date.now (), which DOMTimeStamp returns. DOMTimeStamp is an integer number of milliseconds. To ensure higher accuracy, a new type of DOMHighResTimeStamp was introduced. It is a floating point type, also representing time in milliseconds. But, due to its type, the value can be fractional parts of milliseconds and makes it possible to get an accuracy of up to one thousandth of a millisecond.

User Timing Interface

Now that you have High Resolution time at your disposal, you can use the User Timing interface to get information. The User Timing interface provides functions that allow you to call methods in various places of our application, leaving breadcrumbs like Hansel and Gretel to track where time costs occur.

Using 'mark ()'

The ' mark () ' method is the primary tool in the time analysis toolkit. Mark () allows you to save a timestamp. Especially useful is the ability to name timestamps.

Calling mark () in different parts of the code will determine how long it took to reach this mark.
The specification provides a number of predefined labels that may be useful - 'mark_fully_loaded', 'mark_fully_visible', 'mark_above_the_fold' ”, etc.
For example, you can set a label to determine when the application is fully loaded using the following code:

 window.performance.mark('mark_fully_loaded'); 

Setting named labels in a web application will help collect more runtime information to analyze current time costs.

Calculate measurements with 'measure ()'

Once the timestamps are set, you need to measure the time spent executing the application between them. To do this, use the ' measure () ' method. It is also able to calculate the elapsed time between timestamps and any known event in the PerformanceTiming interface.
For example, you can measure the time between a full DOM load and the moment when your application is fully loaded:

 window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded'); 

Note: in this example, the event name " domComplete " is passed from the PerformanceTiming interface.

Calling measure () keeps the measurement result available for future reference. Keeping the data during the work, the application remains operable and the data can be obtained later, after the end of the work.

Removing tags using 'clearMarks ()'

Sometimes it is useful to be able to get rid of tags that are already created. For example, it may be necessary when conducting batch launches of an application as part of the profiling, when it is necessary to nullify the results before each launch. With the call ' clearMarks ()' it is easy to get rid of any tags that have been set.
This code will remove all existing marks:

 window.performance.clearMarks(); 

Of course, there are some situations in which you should not delete all timestamps. If you need to get rid of specific tags, you just need to pass the name of the mark you want to delete. For example, the code below will remove the mark set in the first example, leaving all the rest:

 window.peformance.clearMarks('mark_fully_loaded'); 

It may also be necessary to remove previously made measurements, so that there is a corresponding 'clearMeasures ()' method. The principle of operation is similar to clearMarks (), but instead of marks, measurements are deleted. For example, the following code will remove the measurements set in measure () in the previous example:

 window.performance.clearMeasures('measure_load_from_dom'); 

If you need to delete all the dimensions, simply call clearMeasures () with no arguments.

Data acquisition

The ability to set marks and measurements is useful, but at some point it will be necessary to obtain data for subsequent analysis. This is also easy to do - all you need is to use the PerformanceTimeline interface.

For example, the method ' getEntriesByType () ' allows you to get all the timestamps or measurements in the form of a list, for later sorting and retrieving information. The list is compiled in chronological order, so that the labels are presented in the order in which they appear in the web application.
The following code returns a list of all the marks that exist in the application:

 var items = window.performance.getEntriesByType('mark'); 

While the following code, returns a list of all dimensions:

 var items = window.performance.getEntriesByType('measure'); 

You can also get a list of named marks. For example, the following code will return a list with one entry containing the mark_fully_loaded mark in the startTime property.

 var items = window.performance.getEntriesByName('mark_fully_loaded'); 

Testing an XHR request (example)

Now, after a brief introduction to the User Timing API, you can use it to analyze the duration of an XMLHttpRequest in the application.

First, you need to change all send () requests to trigger a timestamp and replace success callbacks with a function call that sets up another stamp and then generates a measurement of the duration of the request.

Normal XMLHttpRequest will look something like this:

 var myReq = new XMLHttpRequest(); myReq.open('GET', url, true); myReq.onload = function(e) { do_something(e.responseText); } myReq.send(); 

For the code of the example, you should add a global counter to track the number of requests, and also use it to store measurements for each perfect request:

 var reqCount = 0; var myReq = new XMLHttpRequest(); myReq.open('GET', url, true); myReq.onload = function(e) { window.performance.mark('mark_end_xhr'); reqCount++; window.performance.measure('measure_xhr_' + reqCnt, 'mark_start_xhr', 'mark_end_xhr'); do_something(e.responseText); } 

This code generates dimensions with unique names for each XMLHttpRequest sent. It is assumed that requests are executed sequentially - the code for parallel requests will be a little more complicated. This will serve as an exercise for the reader.

After the web application has made all the requests, you can output them to the console with the following code:

 var items = window.performance.getEntriesByType('measure'); for (var i = 0; i < items.length; ++i) { var req = items[i]; console.log('XHR ' + req.name + ' took ' + req.duration + 'ms'); } 

Conclusion

The User Timing API provides many excellent tools applicable to any aspect of your web application. Reducing the number of “hot spots” in an application can be easily achieved by using API calls throughout the application and post-processing the data to get a picture of the delays. But what if the browser does not support this API? This is not a problem, there is a good emulation that is able to pass the test webpagetest.org . So is it worth the wait? You should try the User Timing API right now, and a new opportunity will appear to achieve greater performance, and your users will say thank you.

Source: https://habr.com/ru/post/210564/


All Articles