-
Notifications
You must be signed in to change notification settings - Fork 20
JavaScript API
This micro-library allows you to gather performance timing data for your webapps and websites by exposing an easy to use API leveraging Navigation Timing, High Resolution Time and User Timing for the browsers that support them. The intended use is to gather the data using the API and then log it to your server for later analysis. Since the actual logging is most likely application-specific, it is not part of this library. However, using something like Underscore's extend function, you can easily add on your own functions, including those for logging.
surfnperf.getNetworkLatency(); // fetchStart to responseEnd
surfnperf.getProcessingLoadTime(); // responseEnd (or pageStart for older browsers) to loadEventEnd
surfnperf.getFullRequestLoadTime(); // navigationStart to loadEventEnd
// Note that if you want to use the above methods as soon as the page load event fires,
// you'll have to wrap that in a setTimeout call so that the load event can fire first:
$(window).load(function() {
setTimeout(function() {
console.log(
'Network Latency:', surfnperf.getNetworkLatency(),
'Processing:', surfnperf.getProcessingLoadTime(),
'Full Request:', surfnperf.getFullRequestLoadTime()
);
}, 0);
});
For a visualization of what exactly all of Surf-N-Perf's Navigation Timing Page Load Timing Data methods expose, view this slide from John Riviello's The Truth About Your Web App's Performance presentation. It shows the above 3 methods plus getNetworkTime
& getServerTime
.
// store a custom key/value
surfnperf.setCustom('customKey', 'custom value');
// retrieve the custom key's value
surfnperf.getCustom('customKey');
The 'pageStart' mark is set as User Timing mark, a DOMHighResTimeStamp mark, and a DOMTimeStamp mark in the <head>
. This mark is set between the 'domLoading' and 'domInteractive' attributes of the PerformanceTiming interface. You may want to use this mark if you want to calculate a duration from the time the HTML Document first starts loading and have that starting point be the same across all browsers regardless of their supported features.
// mark a spot in time as significant
surfnperf.mark('foo');
// return the difference between that significant event and the pageStart mark
surfnperf.duration('pageStart', 'foo');
This is similar to the "Duration from the 'pageStart' mark to a specific event" above, but in this case, it uses the exact 'responseEnd' attribute of Navigation Timing for the browsers that support it. Unsupported browsers fall back to the 'pageStart' mark for all Navigation Timing properties between 'navigationStart' and 'domLoading'.
// mark a spot in time as significant
surfnperf.mark('foo');
// return the difference between that significant event and responseEnd/pageStart
surfnperf.duration('responseEnd','foo');
Note that for browsers that do not support Navigation Timing, 'loadEventEnd' is used for all Navigation Timing properties between ''domInteractive' and 'loadEventEnd'.
// mark a spot in time as significant
surfnperf.mark('bar');
// return the difference between that significant event and when the loadEventEnd event fired
surfnperf.duration('loadEventEnd','bar');
// mark the start of some significant process
surfnperf.eventStart('baz');
// mark the end of some significant process
surfnperf.eventEnd('baz');
// get the duration of that significant process
surfnperf.eventDuration('baz');
For browsers that support High Resolution Time, you can retrieve durations with sub-millisecond accuracy by passing a 'decimalPlaces' option
surfnperf.duration('loadEventEnd','bar',{decimalPlaces:5});
surfnperf.eventDuration('baz',{decimalPlaces:10});
surfnperf.resetEvent('baz');
Duration of a specific event (e.g. AJAX call using Backbone fetch) with additional data
var collection = new Backbone.Collection;
collection.url = '/get-data/';
// mark the start of the AJAX call
surfnperf.eventStart('getData');
collection.fetch({
success: function(collection) {
// mark the end of the AJAX call, set its status to 'success' and the number of items returned as 'items'
surfnperf.eventEnd('getData', {status:'success', items: collection.length});
},
error: function() {
// mark the end of the AJAX call, set its status to 'error'
surfnperf.eventEnd('getData', {status:'error'});
},
});
// And then when you're ready, retrieve the data
surfnperf.eventDuration('getData', {decimalPlaces:2}); // duration of AJAX call, accurate to 2 decimal places
surfnperf.getEventData('getData', 'status'); // status of AJAX call
surfnperf.getEventData('getData', 'items'); // number of items returned
Note, these require at least v1.2.0. Both of these functions accept an optional options
argument that will return values with sub-millisecond accuracy by passing a 'decimalPlaces' option if the browser supports High Resolution Time.
As noted below, you may want to wrap the gathering of this data in a window.requestAnimationFrame
callback as well as a setTimeout
to ensure the data has been recorded.
if(window.requestAnimationFrame) {
window.requestAnimationFrame(function() {
setTimeout(function() {
surfnperf.getFirstPaint(); // Time To First Paint as reported by the browser (available in Chrome & IE>=9)
surfnperf.getFirstPaint({decimalPlaces:2}); // accurate to 2 decimal places
surfnperf.getFirstPaintFrame(); // approximation of Time To First Paint using window.requestAnimationFrame
surfnperf.getFirstPaintFrame({decimalPlaces:2}); // accurate to 2 decimal places
}, 10);
});
}