surfnperf 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +49 -8
- data/app/views/surfnperf/_head.html.erb +40 -3
- data/vendor/assets/javascripts/surfnperf.js +85 -13
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e345d399d2630f3f58b9c21268597cf1d68beb9
|
4
|
+
data.tar.gz: 32baf5b753846d060524f9e195d87010251b5f2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e53a18f7868588de15cb06dfc0b6dbcf9c89bca28ea6694047bbd68fb2fb4e6b26eb950cafb24c0aa39689535e7ced3bde9f378380168a3982d49fbf1e57fb9f
|
7
|
+
data.tar.gz: 0a711e5ab7c218d6274c94d2886e51814e15407cff9648dd08d8e337092ef7feea7775aaf0e0568c728bbb441309cb5d0db03f8dffc33463c701588315cefb87
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
Surf-N-Perf
|
1
|
+
Surf-N-Perf
|
2
2
|
==============
|
3
3
|
|
4
|
-
Micro-library for gathering frontend web page performance data.
|
4
|
+
Micro-library for gathering frontend web page performance data.
|
5
5
|
|
6
6
|
Surf-N-Perf provides a simple to use API to gather [User Timing](http://www.w3.org/TR/user-timing/) and other important performance data in any browser.
|
7
7
|
|
@@ -41,6 +41,42 @@ There are 2 pieces of code that need to be included in your webpage:
|
|
41
41
|
}
|
42
42
|
}
|
43
43
|
|
44
|
+
SURF_N_PERF.visibility = {
|
45
|
+
initialState: document.visibilityState,
|
46
|
+
stateUpdates: [],
|
47
|
+
hiddenProperty: null,
|
48
|
+
stateProperty: null,
|
49
|
+
eventName: null,
|
50
|
+
markChange: function() {
|
51
|
+
var markName = 'visibility' + SURF_N_PERF.visibility.stateUpdates.length;
|
52
|
+
|
53
|
+
if (window.performance) {
|
54
|
+
if (window.performance.mark) {
|
55
|
+
window.performance.mark(markName);
|
56
|
+
}
|
57
|
+
|
58
|
+
if (window.performance.now) {
|
59
|
+
SURF_N_PERF.highResMarks[markName] = window.performance.now();
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
SURF_N_PERF.marks[markName] = new Date().getTime();
|
64
|
+
|
65
|
+
SURF_N_PERF.visibility.stateUpdates.push(document[SURF_N_PERF.visibility.stateProperty]);
|
66
|
+
},
|
67
|
+
};
|
68
|
+
|
69
|
+
if('hidden' in document) {
|
70
|
+
SURF_N_PERF.visibility.hiddenProperty = 'hidden';
|
71
|
+
SURF_N_PERF.visibility.stateProperty = 'visibilityState';
|
72
|
+
SURF_N_PERF.visibility.eventName = 'visibilitychange';
|
73
|
+
} else if('webkitHidden' in document) {
|
74
|
+
SURF_N_PERF.visibility.hiddenProperty = 'webkitHidden';
|
75
|
+
SURF_N_PERF.visibility.stateProperty = 'webkitVisibilityState';
|
76
|
+
SURF_N_PERF.visibility.eventName = 'webkitvisibilitychange';
|
77
|
+
SURF_N_PERF.visibility.initialState = document[SURF_N_PERF.visibility.stateProperty];
|
78
|
+
}
|
79
|
+
|
44
80
|
SURF_N_PERF.setPageLoad = function() {
|
45
81
|
SURF_N_PERF.marks.loadEventEnd = (new Date()).getTime();
|
46
82
|
|
@@ -54,7 +90,7 @@ There are 2 pieces of code that need to be included in your webpage:
|
|
54
90
|
|
55
91
|
if(window.performance && window.performance.now) {
|
56
92
|
SURF_N_PERF.highResMarks.firstPaintFrame = window.performance.now();
|
57
|
-
|
93
|
+
|
58
94
|
if(window.performance.mark) {
|
59
95
|
window.performance.mark('firstPaintFrame');
|
60
96
|
}
|
@@ -62,6 +98,9 @@ There are 2 pieces of code that need to be included in your webpage:
|
|
62
98
|
};
|
63
99
|
|
64
100
|
if(window.addEventListener) {
|
101
|
+
if (SURF_N_PERF.visibility.stateProperty) {
|
102
|
+
document.addEventListener(SURF_N_PERF.visibility.eventName, SURF_N_PERF.visibility.markChange, false);
|
103
|
+
}
|
65
104
|
window.addEventListener('load', SURF_N_PERF.setPageLoad, false);
|
66
105
|
} else {
|
67
106
|
window.attachEvent('onload', SURF_N_PERF.setPageLoad);
|
@@ -73,11 +112,13 @@ There are 2 pieces of code that need to be included in your webpage:
|
|
73
112
|
```
|
74
113
|
|
75
114
|
That provides support for the following:
|
76
|
-
|
77
|
-
- "pageStart"
|
78
|
-
-
|
79
|
-
- A "loadEventEnd" [
|
80
|
-
- A "
|
115
|
+
|
116
|
+
- A `"pageStart"` mark for browsers that do not support [Navigation Timing](http://www.w3.org/TR/navigation-timing/) which can be used to compute durations from when the page first started loading (specifically, this mark falls between the [`domLoading`](http://www.w3.org/TR/navigation-timing/#dom-performancetiming-domloading) and [`domInteractive`](http://www.w3.org/TR/navigation-timing/#dom-performancetiming-dominteractive) attributes of Navigation Timing)
|
117
|
+
- `"pageStart"` marks for browsers that support [High Resolution Time](http://www.w3.org/TR/hr-time/) and/or [User Timing](http://www.w3.org/TR/user-timing/) so that `"pageStart"` can be used as a consistent starting point for duration calculations across all browsers regardless of their supported features
|
118
|
+
- A `"loadEventEnd"` mark for browsers that do not support [Navigation Timing](http://www.w3.org/TR/navigation-timing/) which can be used to compute durations from when the load event of the document is completed ([`loadEventEnd`](http://www.w3.org/TR/navigation-timing/#dom-performancetiming-loadend))
|
119
|
+
- A `"loadEventEnd"` [DOMHighResTimeStamp](http://www.w3.org/TR/hr-time/#sec-DOMHighResTimeStamp) mark for calculating high resolution durations between a Navigation Timing mark and a user mark in browsers that support [High Resolution Time](http://www.w3.org/TR/hr-time/) but don't support [User Timing](http://www.w3.org/TR/user-timing/)
|
120
|
+
- A `"firstPaintFrame"` mark (available in the best possible format for the browser, either a [User Timing Mark](http://www.w3.org/TR/user-timing/#performancemark), [DOMHighResTimeStamp](http://www.w3.org/TR/hr-time/#sec-DOMHighResTimeStamp), or [DOMTimeStamp](https://developer.mozilla.org/en-US/docs/Web/API/DOMTimeStamp)) that approximates the Time To First Paint in browsers that [support `window.requestAnimationFrame`](http://caniuse.com/#feat=requestanimationframe).
|
121
|
+
- The initial `visibilityState` as well as listeners for the `"visibilitychange"` event, enabling the ability to calculate how much time the page was hidden when you call `surfnperf.getHiddenTime()`. This is of particular importance as [Chrome as of version 57](https://developers.google.com/web/updates/2017/03/background_tabs) and [Firefox as of version 57](https://blog.mozilla.org/blog/2017/09/26/firefox-quantum-beta-developer-edition/) limit the resources assigned to background (hidden) tabs.
|
81
122
|
|
82
123
|
**2.** Then just drop the [surfnperf.min.js](https://github.com/Comcast/Surf-N-Perf/blob/master/surfnperf.min.js) in your codebase and reference that JavaScript file in your HTML document. If you're using [RequireJS](http://requirejs.org/) or [Browserify](http://browserify.org/), it registers itself as 'surfnperf'.
|
83
124
|
|
@@ -15,6 +15,42 @@
|
|
15
15
|
}
|
16
16
|
}
|
17
17
|
|
18
|
+
SURF_N_PERF.visibility = {
|
19
|
+
initialState: document.visibilityState,
|
20
|
+
stateUpdates: [],
|
21
|
+
hiddenProperty: null,
|
22
|
+
stateProperty: null,
|
23
|
+
eventName: null,
|
24
|
+
markChange: function() {
|
25
|
+
var markName = 'visibility' + SURF_N_PERF.visibility.stateUpdates.length;
|
26
|
+
|
27
|
+
if (window.performance) {
|
28
|
+
if (window.performance.mark) {
|
29
|
+
window.performance.mark(markName);
|
30
|
+
}
|
31
|
+
|
32
|
+
if (window.performance.now) {
|
33
|
+
SURF_N_PERF.highResMarks[markName] = window.performance.now();
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
SURF_N_PERF.marks[markName] = new Date().getTime();
|
38
|
+
|
39
|
+
SURF_N_PERF.visibility.stateUpdates.push(document[SURF_N_PERF.visibility.stateProperty]);
|
40
|
+
},
|
41
|
+
};
|
42
|
+
|
43
|
+
if('hidden' in document) {
|
44
|
+
SURF_N_PERF.visibility.hiddenProperty = 'hidden';
|
45
|
+
SURF_N_PERF.visibility.stateProperty = 'visibilityState';
|
46
|
+
SURF_N_PERF.visibility.eventName = 'visibilitychange';
|
47
|
+
} else if('webkitHidden' in document) {
|
48
|
+
SURF_N_PERF.visibility.hiddenProperty = 'webkitHidden';
|
49
|
+
SURF_N_PERF.visibility.stateProperty = 'webkitVisibilityState';
|
50
|
+
SURF_N_PERF.visibility.eventName = 'webkitvisibilitychange';
|
51
|
+
SURF_N_PERF.visibility.initialState = document[SURF_N_PERF.visibility.stateProperty];
|
52
|
+
}
|
53
|
+
|
18
54
|
SURF_N_PERF.setPageLoad = function() {
|
19
55
|
SURF_N_PERF.marks.loadEventEnd = (new Date()).getTime();
|
20
56
|
|
@@ -28,7 +64,7 @@
|
|
28
64
|
|
29
65
|
if(window.performance && window.performance.now) {
|
30
66
|
SURF_N_PERF.highResMarks.firstPaintFrame = window.performance.now();
|
31
|
-
|
67
|
+
|
32
68
|
if(window.performance.mark) {
|
33
69
|
window.performance.mark('firstPaintFrame');
|
34
70
|
}
|
@@ -36,13 +72,14 @@
|
|
36
72
|
};
|
37
73
|
|
38
74
|
if(window.addEventListener) {
|
75
|
+
if (SURF_N_PERF.visibility.stateProperty) {
|
76
|
+
document.addEventListener(SURF_N_PERF.visibility.eventName, SURF_N_PERF.visibility.markChange, false);
|
77
|
+
}
|
39
78
|
window.addEventListener('load', SURF_N_PERF.setPageLoad, false);
|
40
79
|
} else {
|
41
80
|
window.attachEvent('onload', SURF_N_PERF.setPageLoad);
|
42
81
|
}
|
43
|
-
|
44
82
|
if (window.requestAnimationFrame) {
|
45
83
|
window.requestAnimationFrame(SURF_N_PERF.setFirstPaint);
|
46
84
|
}
|
47
|
-
|
48
85
|
</script>
|
@@ -262,37 +262,59 @@
|
|
262
262
|
return this._round(b - a, options);
|
263
263
|
};
|
264
264
|
|
265
|
-
SNPProto._measureName = function(
|
266
|
-
return '_SNP_' +
|
265
|
+
SNPProto._measureName = function(startMark, endMark) {
|
266
|
+
return '_SNP_' + startMark + '_TO_' + endMark;
|
267
267
|
};
|
268
268
|
|
269
|
-
SNPProto._setMeasure = function(
|
269
|
+
SNPProto._setMeasure = function(startMark, endMark) {
|
270
270
|
try {
|
271
|
-
this.userTiming().measure(this._measureName(
|
271
|
+
this.userTiming().measure(this._measureName(startMark, endMark), startMark, endMark);
|
272
272
|
} catch(e) {
|
273
273
|
if(window.console && window.console.error) {
|
274
274
|
if(e && e.message) {
|
275
275
|
console.error("Surf-N-Perf Exception:", e.message);
|
276
276
|
} else {
|
277
|
-
console.error("Surf-N-Perf Exception: at least one of these events/marks is not available yet",
|
277
|
+
console.error("Surf-N-Perf Exception: at least one of these events/marks is not available yet", startMark, endMark);
|
278
278
|
}
|
279
279
|
}
|
280
280
|
}
|
281
281
|
};
|
282
282
|
|
283
|
-
SNPProto._getMeasureDuration = function(
|
284
|
-
var measure = this.userTiming().getEntriesByName(this._measureName(
|
283
|
+
SNPProto._getMeasureDuration = function(startMark, endMark) {
|
284
|
+
var measure = this.userTiming().getEntriesByName(this._measureName(startMark, endMark))[0] || {};
|
285
285
|
return measure.duration;
|
286
286
|
};
|
287
287
|
|
288
|
-
|
288
|
+
/**
|
289
|
+
* Marks the current time
|
290
|
+
*
|
291
|
+
* @returns {String} name generated for the mark
|
292
|
+
* @memberOf SurfNPerf
|
293
|
+
*/
|
294
|
+
SNPProto.markNow = function() {
|
295
|
+
var eventKey = '_NOW_' + this.now('DOM');
|
296
|
+
this.mark(eventKey);
|
297
|
+
return eventKey;
|
298
|
+
};
|
299
|
+
|
300
|
+
/**
|
301
|
+
* Returns the duration between two marks
|
302
|
+
*
|
303
|
+
* @param {String} startMark name of the first mark
|
304
|
+
* @param {String} [endMark] optional name of the second mark
|
305
|
+
* @returns {Number} duration between the two specified marks. If the endMark is not specified, returns the duration between the startMark and the current time
|
306
|
+
* @memberOf SurfNPerf
|
307
|
+
*/
|
308
|
+
SNPProto.duration = function(startMark, endMark, options) {
|
309
|
+
endMark = endMark || this.markNow();
|
310
|
+
|
289
311
|
if(this._userTiming) {
|
290
|
-
this._setMeasure(
|
291
|
-
return this._round(this._getMeasureDuration(
|
292
|
-
} else if(this._highResTime &&
|
293
|
-
return this._round(this.getMark(
|
312
|
+
this._setMeasure(startMark, endMark);
|
313
|
+
return this._round(this._getMeasureDuration(startMark, endMark), options);
|
314
|
+
} else if(this._highResTime && startMark === 'navigationStart' && !this._isTimingMark(endMark)) {
|
315
|
+
return this._round(this.getMark(endMark), options);
|
294
316
|
} else {
|
295
|
-
return this._roundedDuration(this._getDurationMark(
|
317
|
+
return this._roundedDuration(this._getDurationMark(startMark), this._getDurationMark(endMark), options);
|
296
318
|
}
|
297
319
|
};
|
298
320
|
|
@@ -446,6 +468,56 @@
|
|
446
468
|
}
|
447
469
|
};
|
448
470
|
|
471
|
+
/**
|
472
|
+
* Is the page hidden or not, as reported by the Page Visibility API
|
473
|
+
*
|
474
|
+
* @returns {boolean} true if the page is in a state considered to be hidden to the user, and false otherwise.
|
475
|
+
* @memberOf SurfNPerf
|
476
|
+
*/
|
477
|
+
SNPProto.isHidden = function() {
|
478
|
+
if(SURF_N_PERF.visibility && SURF_N_PERF.visibility.hiddenProperty) {
|
479
|
+
return document[SURF_N_PERF.visibility.hiddenProperty];
|
480
|
+
} else {
|
481
|
+
return null;
|
482
|
+
}
|
483
|
+
};
|
484
|
+
|
485
|
+
/**
|
486
|
+
* Total time a page is not visible, as reported by the Page Visibility API
|
487
|
+
*
|
488
|
+
* @returns {integer} time in ms
|
489
|
+
* @memberOf SurfNPerf
|
490
|
+
*/
|
491
|
+
SNPProto.getHiddenTime = function(options) {
|
492
|
+
var total = 0,
|
493
|
+
states = [],
|
494
|
+
i,
|
495
|
+
length,
|
496
|
+
getMarkName = function(index) {
|
497
|
+
return index === 0 ? 'navigationStart' : 'visibility' + (index - 1);
|
498
|
+
};
|
499
|
+
|
500
|
+
if(SURF_N_PERF.visibility && SURF_N_PERF.visibility.initialState && SURF_N_PERF.visibility.stateUpdates) {
|
501
|
+
states = states.concat(SURF_N_PERF.visibility.initialState, SURF_N_PERF.visibility.stateUpdates);
|
502
|
+
length = states.length;
|
503
|
+
for(i = 1; i < length; i++) {
|
504
|
+
if(states[i - 1] !== 'visible' && states[i] === 'visible') {
|
505
|
+
total += this.duration(getMarkName(i - 1), getMarkName(i), {
|
506
|
+
decimalPlaces: 10
|
507
|
+
});
|
508
|
+
}
|
509
|
+
}
|
510
|
+
if(states[length - 1] !== 'visible') {
|
511
|
+
total += this.duration(getMarkName(length - 1), null, {
|
512
|
+
decimalPlaces: 10
|
513
|
+
});
|
514
|
+
}
|
515
|
+
return this._round(total, options);
|
516
|
+
} else {
|
517
|
+
return null;
|
518
|
+
}
|
519
|
+
};
|
520
|
+
|
449
521
|
return new SurfNPerf();
|
450
522
|
|
451
523
|
}));
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: surfnperf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Riviello
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -73,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
73
|
version: '0'
|
74
74
|
requirements: []
|
75
75
|
rubyforge_project:
|
76
|
-
rubygems_version: 2.6.
|
76
|
+
rubygems_version: 2.6.13
|
77
77
|
signing_key:
|
78
78
|
specification_version: 4
|
79
79
|
summary: Micro-library for gathering frontend web page performance data
|