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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2ebf230cbfd8dc288c35183b576965432d010f93
4
- data.tar.gz: 5ea5493fe01a15c3e89e310a85619c5a10f737c7
3
+ metadata.gz: 6e345d399d2630f3f58b9c21268597cf1d68beb9
4
+ data.tar.gz: 32baf5b753846d060524f9e195d87010251b5f2e
5
5
  SHA512:
6
- metadata.gz: a7d39899a860a238186e9228f1b404ffee2a09cd79ef43f2e415153a10f685730d41eba4af6f66b6ad2e51b413b8bace3e567a5c831f47d1c5dfc7555dfb7874
7
- data.tar.gz: 57d0f1897109c30d5f1e3a3084e8277ad826916b0b6e767947053d0c5c390e429f490f7fc1e0dd18d2b504c6bab63734b01de2e939919e81808e10d7e31bcdd4
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
- - 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)
77
- - "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
78
- - 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))
79
- - 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/)
80
- - 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).
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(a, b) {
266
- return '_SNP_' + a + '_TO_' + b;
265
+ SNPProto._measureName = function(startMark, endMark) {
266
+ return '_SNP_' + startMark + '_TO_' + endMark;
267
267
  };
268
268
 
269
- SNPProto._setMeasure = function(a, b) {
269
+ SNPProto._setMeasure = function(startMark, endMark) {
270
270
  try {
271
- this.userTiming().measure(this._measureName(a, b), a, b);
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", a, b);
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(a, b) {
284
- var measure = this.userTiming().getEntriesByName(this._measureName(a, b))[0] || {};
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
- SNPProto.duration = function(a, b, options) {
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(a, b);
291
- return this._round(this._getMeasureDuration(a, b), options);
292
- } else if(this._highResTime && a === 'navigationStart' && !this._isTimingMark(b)) {
293
- return this._round(this.getMark(b), options);
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(a), this._getDurationMark(b), options);
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.0
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-02-06 00:00:00.000000000 Z
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.10
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