surfnperf 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|