@atlaskit/insm 0.1.3 → 0.2.1
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.
- package/CHANGELOG.md +17 -0
- package/README.md +3 -0
- package/dist/cjs/insm-period.js +20 -2
- package/dist/cjs/insm-session.js +26 -9
- package/dist/cjs/insm.js +26 -12
- package/dist/cjs/session-measurers/LongAnimationFrameMeasurer.js +76 -34
- package/dist/es2019/insm-period.js +19 -1
- package/dist/es2019/insm-session.js +21 -6
- package/dist/es2019/insm.js +26 -12
- package/dist/es2019/session-measurers/LongAnimationFrameMeasurer.js +61 -34
- package/dist/esm/insm-period.js +19 -1
- package/dist/esm/insm-session.js +26 -9
- package/dist/esm/insm.js +26 -12
- package/dist/esm/session-measurers/LongAnimationFrameMeasurer.js +77 -34
- package/dist/types/insm-period.d.ts +21 -2
- package/dist/types/insm-session.d.ts +8 -0
- package/dist/types/insm.d.ts +11 -4
- package/dist/types/session-measurers/LongAnimationFrameMeasurer.d.ts +26 -24
- package/dist/types/types.d.ts +25 -25
- package/dist/types-ts4.5/insm-period.d.ts +21 -2
- package/dist/types-ts4.5/insm-session.d.ts +8 -0
- package/dist/types-ts4.5/insm.d.ts +11 -4
- package/dist/types-ts4.5/session-measurers/LongAnimationFrameMeasurer.d.ts +26 -24
- package/dist/types-ts4.5/types.d.ts +25 -25
- package/package.json +8 -3
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
// Script timing data we want to track
|
|
3
|
+
|
|
2
4
|
export class LongAnimationFrameMeasurer {
|
|
3
5
|
constructor(options) {
|
|
4
|
-
_defineProperty(this, "
|
|
6
|
+
_defineProperty(this, "longestScriptTimings", []);
|
|
5
7
|
_defineProperty(this, "minimumIndex", -1);
|
|
6
8
|
_defineProperty(this, "minimumDuration", Infinity);
|
|
7
9
|
this.options = options;
|
|
@@ -20,48 +22,72 @@ export class LongAnimationFrameMeasurer {
|
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
24
|
handleBatch(batch) {
|
|
23
|
-
let len = this.longestAnimationFrames.length;
|
|
24
25
|
for (let batchIndex = 0; batchIndex < batch.length; batchIndex++) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
const animationFrame = batch[batchIndex];
|
|
27
|
+
|
|
28
|
+
// Only process frames that exceed the reporting threshold
|
|
29
|
+
if (animationFrame.duration < this.options.reportingThreshold) {
|
|
28
30
|
continue;
|
|
29
31
|
}
|
|
30
|
-
const longAnimationFrameEntry = Object.assign(batch[batchIndex], {
|
|
31
|
-
runningFeatures: Array.from(this.options.insmSession.runningFeatures)
|
|
32
|
-
});
|
|
33
32
|
|
|
34
|
-
//
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
this.minimumDuration = longAnimationFrameEntry.duration;
|
|
39
|
-
this.minimumIndex = len;
|
|
33
|
+
// Process all scripts in this long animation frame
|
|
34
|
+
if (animationFrame.scripts && animationFrame.scripts.length > 0) {
|
|
35
|
+
for (const script of animationFrame.scripts) {
|
|
36
|
+
this.processScript(script, animationFrame);
|
|
40
37
|
}
|
|
41
|
-
len++;
|
|
42
|
-
continue;
|
|
43
38
|
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
createScriptTiming(script, animationFrame) {
|
|
42
|
+
return {
|
|
43
|
+
duration: script.duration,
|
|
44
|
+
forcedStyleAndLayoutDuration: script.forcedStyleAndLayoutDuration,
|
|
45
|
+
invoker: script.invoker,
|
|
46
|
+
invokerType: script.invokerType,
|
|
47
|
+
sourceCharPosition: script.sourceCharPosition,
|
|
48
|
+
sourceFunctionName: script.sourceFunctionName,
|
|
49
|
+
sourceURL: script.sourceURL,
|
|
50
|
+
features: Array.from(this.options.insmSession.runningFeatures),
|
|
51
|
+
afDuration: animationFrame.duration
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
processScript(script, animationFrame) {
|
|
55
|
+
const scriptDuration = script.duration;
|
|
56
|
+
const len = this.longestScriptTimings.length;
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
58
|
+
// Not yet at capacity: append and update min tracking incrementally
|
|
59
|
+
if (len < this.options.limit) {
|
|
60
|
+
const scriptTiming = this.createScriptTiming(script, animationFrame);
|
|
61
|
+
this.longestScriptTimings[len] = scriptTiming;
|
|
62
|
+
if (len === 0 || scriptDuration < this.minimumDuration) {
|
|
63
|
+
this.minimumDuration = scriptDuration;
|
|
64
|
+
this.minimumIndex = len;
|
|
48
65
|
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
49
68
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (this.longestAnimationFrames[i].duration < _possibleNewMinimumDuration) {
|
|
56
|
-
_possiblyNewMinimumIndex = i;
|
|
57
|
-
_possibleNewMinimumDuration = this.longestAnimationFrames[i].duration;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
69
|
+
// At capacity: only do work if we beat the current min
|
|
70
|
+
if (scriptDuration <= this.minimumDuration) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const scriptTiming = this.createScriptTiming(script, animationFrame);
|
|
60
74
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
// Replace the current min
|
|
76
|
+
this.longestScriptTimings[this.minimumIndex] = scriptTiming;
|
|
77
|
+
|
|
78
|
+
// Find new minimum
|
|
79
|
+
let newMinimumIndex = 0;
|
|
80
|
+
let newMinimumDuration = this.longestScriptTimings[0].duration;
|
|
81
|
+
for (let i = 1; i < this.options.limit; i++) {
|
|
82
|
+
if (this.longestScriptTimings[i].duration < newMinimumDuration) {
|
|
83
|
+
newMinimumIndex = i;
|
|
84
|
+
newMinimumDuration = this.longestScriptTimings[i].duration;
|
|
85
|
+
}
|
|
64
86
|
}
|
|
87
|
+
|
|
88
|
+
// Update the min tracking
|
|
89
|
+
this.minimumIndex = newMinimumIndex;
|
|
90
|
+
this.minimumDuration = newMinimumDuration;
|
|
65
91
|
}
|
|
66
92
|
|
|
67
93
|
/**
|
|
@@ -79,10 +105,10 @@ export class LongAnimationFrameMeasurer {
|
|
|
79
105
|
}
|
|
80
106
|
|
|
81
107
|
/**
|
|
82
|
-
* Returns the current tracked longest
|
|
108
|
+
* Returns the current tracked longest script timings sorted by duration
|
|
83
109
|
*/
|
|
84
110
|
get current() {
|
|
85
|
-
const copy = this.
|
|
111
|
+
const copy = this.longestScriptTimings.slice();
|
|
86
112
|
copy.sort((a, b) => b.duration - a.duration);
|
|
87
113
|
return copy;
|
|
88
114
|
}
|
|
@@ -97,5 +123,6 @@ export class LongAnimationFrameMeasurer {
|
|
|
97
123
|
}
|
|
98
124
|
|
|
99
125
|
// Based on https://github.com/GoogleChrome/web-vitals/blob/1b872cf5f2159e8ace0e98d55d8eb54fb09adfbe/src/types.ts#L129
|
|
126
|
+
// exported for use in test file
|
|
100
127
|
|
|
101
128
|
// Based on https://github.com/GoogleChrome/web-vitals/blob/1b872cf5f2159e8ace0e98d55d8eb54fb09adfbe/src/types.ts#L129
|
package/dist/esm/insm-period.js
CHANGED
|
@@ -5,7 +5,7 @@ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol
|
|
|
5
5
|
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
6
6
|
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
7
7
|
/* eslint-disable @repo/internal/dom-events/no-unsafe-event-listeners */
|
|
8
|
-
|
|
8
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
9
9
|
export var PeriodTracking = /*#__PURE__*/function () {
|
|
10
10
|
function PeriodTracking(session) {
|
|
11
11
|
_classCallCheck(this, PeriodTracking);
|
|
@@ -151,6 +151,24 @@ export var PeriodTracking = /*#__PURE__*/function () {
|
|
|
151
151
|
key: "endResults",
|
|
152
152
|
get: function get() {
|
|
153
153
|
this.changePeriodAndTrackLast(this.state);
|
|
154
|
+
if (fg('cc_editor_insm_fix_attributes')) {
|
|
155
|
+
return {
|
|
156
|
+
active: {
|
|
157
|
+
features: Array.from(this.periodMeasurements.active.features),
|
|
158
|
+
heavyTasks: Array.from(this.periodMeasurements.active.heavyTasks),
|
|
159
|
+
measurements: this.periodMeasurements.active.measurements,
|
|
160
|
+
duration: this.periodMeasurements.active.duration,
|
|
161
|
+
count: this.periodMeasurements.active.count
|
|
162
|
+
},
|
|
163
|
+
inactive: {
|
|
164
|
+
features: Array.from(this.periodMeasurements.inactive.features),
|
|
165
|
+
heavyTasks: Array.from(this.periodMeasurements.inactive.heavyTasks),
|
|
166
|
+
measurements: this.periodMeasurements.inactive.measurements,
|
|
167
|
+
duration: this.periodMeasurements.inactive.duration,
|
|
168
|
+
count: this.periodMeasurements.inactive.count
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
154
172
|
return this.periodMeasurements;
|
|
155
173
|
}
|
|
156
174
|
}, {
|
package/dist/esm/insm-session.js
CHANGED
|
@@ -15,11 +15,14 @@ import { LongAnimationFrameMeasurer } from './session-measurers/LongAnimationFra
|
|
|
15
15
|
* Only intended for internal use.
|
|
16
16
|
*
|
|
17
17
|
* Exported for consumers who may require the type.
|
|
18
|
+
*
|
|
19
|
+
* Note: Events are not reliably fired from mobile browsers (ie. when a browser is closed when not in use)
|
|
18
20
|
*/
|
|
19
21
|
export var INSMSession = /*#__PURE__*/function () {
|
|
20
22
|
function INSMSession(experienceKey, experienceProperties, insm) {
|
|
21
23
|
_classCallCheck(this, INSMSession);
|
|
22
24
|
_defineProperty(this, "startedAt", performance.now());
|
|
25
|
+
_defineProperty(this, "pageLoadTime", null);
|
|
23
26
|
_defineProperty(this, "running", true);
|
|
24
27
|
_defineProperty(this, "addedProperties", []);
|
|
25
28
|
_defineProperty(this, "runningFeatures", new Set());
|
|
@@ -33,12 +36,18 @@ export var INSMSession = /*#__PURE__*/function () {
|
|
|
33
36
|
insmSession: this,
|
|
34
37
|
reportingThreshold: 500
|
|
35
38
|
});
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Note: Events are not reliably fired from mobile browsers (ie. when a browser is closed when not in use)
|
|
39
|
-
*/
|
|
40
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Completes the page load timing. This is called automatically when ending a heavy task
|
|
43
|
+
* with the key 'PageLoad'.
|
|
44
|
+
*/
|
|
41
45
|
return _createClass(INSMSession, [{
|
|
46
|
+
key: "completePageLoad",
|
|
47
|
+
value: function completePageLoad() {
|
|
48
|
+
this.pageLoadTime = performance.now() - this.startedAt;
|
|
49
|
+
}
|
|
50
|
+
}, {
|
|
42
51
|
key: "updateExperienceKey",
|
|
43
52
|
value: function updateExperienceKey(experienceKey) {
|
|
44
53
|
this.experienceKey = experienceKey;
|
|
@@ -138,7 +147,7 @@ export var INSMSession = /*#__PURE__*/function () {
|
|
|
138
147
|
}, {
|
|
139
148
|
key: "end",
|
|
140
149
|
value: function end(endDetails) {
|
|
141
|
-
var _this$insm$analyticsW;
|
|
150
|
+
var _periodResults$active, _periodResults$active2, _periodResults$active3, _periodResults$active4, _this$insm$analyticsW;
|
|
142
151
|
if (this.running === false) {
|
|
143
152
|
// If an experience has already been ended -- don't repeat the ending
|
|
144
153
|
return;
|
|
@@ -171,19 +180,27 @@ export var INSMSession = /*#__PURE__*/function () {
|
|
|
171
180
|
var operationalEvent = {
|
|
172
181
|
actionSubject: 'insm',
|
|
173
182
|
action: 'measured',
|
|
174
|
-
attributes: _objectSpread(_objectSpread({}, evaluatedAddedProperties), {}, {
|
|
183
|
+
attributes: _objectSpread(_objectSpread(_objectSpread({}, evaluatedAddedProperties), {}, {
|
|
175
184
|
experienceKey: this.experienceKey,
|
|
176
185
|
initial: this.experienceProperties.initial,
|
|
177
186
|
contentId: this.experienceProperties.contentId,
|
|
178
187
|
timing: {
|
|
179
188
|
startedAt: this.startedAt,
|
|
189
|
+
// Note: this will not match up with the periods sum of durations, as it includes
|
|
190
|
+
// time paused when heavy tasks were running, and/or the page is in the background.
|
|
180
191
|
duration: duration
|
|
181
192
|
},
|
|
182
193
|
periods: periodResults,
|
|
183
|
-
endDetails: endDetails
|
|
184
|
-
|
|
194
|
+
endDetails: endDetails
|
|
195
|
+
}, expValEquals('cc_editor_insm_outlier_events', 'cohort', 'test') ? {
|
|
196
|
+
longScripts: this.longAnimationFrameMeasurer.current,
|
|
197
|
+
pageLoadTime: this.pageLoadTime,
|
|
198
|
+
deviceDetails: getDeviceDetails()
|
|
199
|
+
} : {}), {}, {
|
|
200
|
+
// these health attributes drive our SLOs
|
|
201
|
+
healthAFPS: (_periodResults$active = periodResults.active.measurements.afps) !== null && _periodResults$active !== void 0 && _periodResults$active.average ? ((_periodResults$active2 = periodResults.active.measurements.afps) === null || _periodResults$active2 === void 0 ? void 0 : _periodResults$active2.average) >= 50 : undefined,
|
|
202
|
+
healthINP: (_periodResults$active3 = periodResults.active.measurements.inp) !== null && _periodResults$active3 !== void 0 && _periodResults$active3.average ? ((_periodResults$active4 = periodResults.active.measurements.inp) === null || _periodResults$active4 === void 0 ? void 0 : _periodResults$active4.average) >= 200 : undefined
|
|
185
203
|
}),
|
|
186
|
-
deviceDetails: expValEquals('cc_editor_interactivity_monitoring', 'isEnabled', true) ? getDeviceDetails() : undefined,
|
|
187
204
|
highPriority: true,
|
|
188
205
|
tags: ['editor'],
|
|
189
206
|
source: 'unknown'
|
package/dist/esm/insm.js
CHANGED
|
@@ -4,6 +4,7 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
|
4
4
|
import { INSMSession } from './insm-session';
|
|
5
5
|
import { AnimationFPSIM } from './period-measurers/afps';
|
|
6
6
|
import { INPTracker } from './inp-measurers/inp';
|
|
7
|
+
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
7
8
|
export var INSM = /*#__PURE__*/function () {
|
|
8
9
|
function INSM(options) {
|
|
9
10
|
var _this = this;
|
|
@@ -46,15 +47,18 @@ export var INSM = /*#__PURE__*/function () {
|
|
|
46
47
|
* Starts a heavy task in the currently running session.
|
|
47
48
|
*
|
|
48
49
|
* This also pauses measurement.
|
|
50
|
+
*
|
|
51
|
+
* For PageLoads using the key 'PageLoad' will mean the heavy task duration
|
|
52
|
+
* is added to the insm session event as pageLoadTime.
|
|
49
53
|
*/
|
|
50
54
|
return _createClass(INSM, [{
|
|
51
55
|
key: "startHeavyTask",
|
|
52
56
|
value: function startHeavyTask(heavyTaskName) {
|
|
53
|
-
var _this$runningSession2, _this$runningSession3, _this$
|
|
57
|
+
var _this$runningSession2, _this$runningSession3, _this$runningSession4;
|
|
54
58
|
this.runningHeavyTasks.add(heavyTaskName);
|
|
55
59
|
(_this$runningSession2 = this.runningSession) === null || _this$runningSession2 === void 0 || (_this$runningSession2 = _this$runningSession2.periodTracking) === null || _this$runningSession2 === void 0 || _this$runningSession2.startHeavyTask(heavyTaskName);
|
|
56
60
|
(_this$runningSession3 = this.runningSession) === null || _this$runningSession3 === void 0 || _this$runningSession3.periodTracking.pause(heavyTaskName);
|
|
57
|
-
(_this$
|
|
61
|
+
(_this$runningSession4 = this.runningSession) === null || _this$runningSession4 === void 0 || _this$runningSession4.longAnimationFrameMeasurer.pause();
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
/**
|
|
@@ -63,12 +67,18 @@ export var INSM = /*#__PURE__*/function () {
|
|
|
63
67
|
}, {
|
|
64
68
|
key: "endHeavyTask",
|
|
65
69
|
value: function endHeavyTask(heavyTaskName) {
|
|
66
|
-
var _this$
|
|
70
|
+
var _this$runningSession5;
|
|
67
71
|
this.runningHeavyTasks.delete(heavyTaskName);
|
|
68
|
-
(_this$
|
|
72
|
+
(_this$runningSession5 = this.runningSession) === null || _this$runningSession5 === void 0 || _this$runningSession5.periodTracking.resume(heavyTaskName);
|
|
69
73
|
if (this.runningHeavyTasks.size === 0) {
|
|
70
|
-
var _this$
|
|
71
|
-
(_this$
|
|
74
|
+
var _this$runningSession6;
|
|
75
|
+
(_this$runningSession6 = this.runningSession) === null || _this$runningSession6 === void 0 || _this$runningSession6.longAnimationFrameMeasurer.resume();
|
|
76
|
+
}
|
|
77
|
+
if (expValEquals('cc_editor_insm_outlier_events', 'cohort', 'test')) {
|
|
78
|
+
if (heavyTaskName === 'PageLoad') {
|
|
79
|
+
var _this$runningSession7;
|
|
80
|
+
(_this$runningSession7 = this.runningSession) === null || _this$runningSession7 === void 0 || _this$runningSession7.completePageLoad();
|
|
81
|
+
}
|
|
72
82
|
}
|
|
73
83
|
}
|
|
74
84
|
|
|
@@ -76,15 +86,19 @@ export var INSM = /*#__PURE__*/function () {
|
|
|
76
86
|
* Call this when starting a new experience. This is expected to be wired to the product
|
|
77
87
|
* routing solution.
|
|
78
88
|
*
|
|
79
|
-
* It's expected this call will be paired with a `insm.session.startHeavyTask('
|
|
80
|
-
* so that performance degradations linked
|
|
89
|
+
* It's expected this call will be paired with a `insm.session.startHeavyTask('PageLoad')` and
|
|
90
|
+
* subsequent `insm.session.endHeavyTask('PageLoad')` so that performance degradations linked
|
|
91
|
+
* to the page initialisation are excluded from the active interactivity monitoring.
|
|
92
|
+
*
|
|
93
|
+
* Using the key 'PageLoad' is special and will result in the heavy task duration being added to the
|
|
94
|
+
* insm session event as pageLoadTime.
|
|
81
95
|
*
|
|
82
96
|
*
|
|
83
97
|
* ```ts
|
|
84
98
|
* insm.start('edit-page', { initial: true, contentId: '9001' })
|
|
85
|
-
* insm.session.startHeavyTask(''
|
|
99
|
+
* insm.session.startHeavyTask('PageLoad')
|
|
86
100
|
* // ... heavy initialisation work
|
|
87
|
-
* insm.session.endHeavyTask(''
|
|
101
|
+
* insm.session.endHeavyTask('PageLoad')
|
|
88
102
|
* ```
|
|
89
103
|
*/
|
|
90
104
|
}, {
|
|
@@ -131,8 +145,8 @@ export var INSM = /*#__PURE__*/function () {
|
|
|
131
145
|
}, {
|
|
132
146
|
key: "stopEarly",
|
|
133
147
|
value: function stopEarly(reasonKey, description) {
|
|
134
|
-
var _this$
|
|
135
|
-
(_this$
|
|
148
|
+
var _this$runningSession8;
|
|
149
|
+
(_this$runningSession8 = this.runningSession) === null || _this$runningSession8 === void 0 || _this$runningSession8.earlyStop(reasonKey, description);
|
|
136
150
|
}
|
|
137
151
|
|
|
138
152
|
/**
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
2
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
3
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
5
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
6
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
7
|
+
// Script timing data we want to track
|
|
8
|
+
|
|
4
9
|
export var LongAnimationFrameMeasurer = /*#__PURE__*/function () {
|
|
5
10
|
function LongAnimationFrameMeasurer(options) {
|
|
6
11
|
var _this = this;
|
|
7
12
|
_classCallCheck(this, LongAnimationFrameMeasurer);
|
|
8
|
-
_defineProperty(this, "
|
|
13
|
+
_defineProperty(this, "longestScriptTimings", []);
|
|
9
14
|
_defineProperty(this, "minimumIndex", -1);
|
|
10
15
|
_defineProperty(this, "minimumDuration", Infinity);
|
|
11
16
|
this.options = options;
|
|
@@ -26,48 +31,85 @@ export var LongAnimationFrameMeasurer = /*#__PURE__*/function () {
|
|
|
26
31
|
return _createClass(LongAnimationFrameMeasurer, [{
|
|
27
32
|
key: "handleBatch",
|
|
28
33
|
value: function handleBatch(batch) {
|
|
29
|
-
var len = this.longestAnimationFrames.length;
|
|
30
34
|
for (var batchIndex = 0; batchIndex < batch.length; batchIndex++) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
var animationFrame = batch[batchIndex];
|
|
36
|
+
|
|
37
|
+
// Only process frames that exceed the reporting threshold
|
|
38
|
+
if (animationFrame.duration < this.options.reportingThreshold) {
|
|
34
39
|
continue;
|
|
35
40
|
}
|
|
36
|
-
var longAnimationFrameEntry = Object.assign(batch[batchIndex], {
|
|
37
|
-
runningFeatures: Array.from(this.options.insmSession.runningFeatures)
|
|
38
|
-
});
|
|
39
41
|
|
|
40
|
-
//
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
// Process all scripts in this long animation frame
|
|
43
|
+
if (animationFrame.scripts && animationFrame.scripts.length > 0) {
|
|
44
|
+
var _iterator = _createForOfIteratorHelper(animationFrame.scripts),
|
|
45
|
+
_step;
|
|
46
|
+
try {
|
|
47
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
48
|
+
var script = _step.value;
|
|
49
|
+
this.processScript(script, animationFrame);
|
|
50
|
+
}
|
|
51
|
+
} catch (err) {
|
|
52
|
+
_iterator.e(err);
|
|
53
|
+
} finally {
|
|
54
|
+
_iterator.f();
|
|
46
55
|
}
|
|
47
|
-
len++;
|
|
48
|
-
continue;
|
|
49
56
|
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}, {
|
|
60
|
+
key: "createScriptTiming",
|
|
61
|
+
value: function createScriptTiming(script, animationFrame) {
|
|
62
|
+
return {
|
|
63
|
+
duration: script.duration,
|
|
64
|
+
forcedStyleAndLayoutDuration: script.forcedStyleAndLayoutDuration,
|
|
65
|
+
invoker: script.invoker,
|
|
66
|
+
invokerType: script.invokerType,
|
|
67
|
+
sourceCharPosition: script.sourceCharPosition,
|
|
68
|
+
sourceFunctionName: script.sourceFunctionName,
|
|
69
|
+
sourceURL: script.sourceURL,
|
|
70
|
+
features: Array.from(this.options.insmSession.runningFeatures),
|
|
71
|
+
afDuration: animationFrame.duration
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}, {
|
|
75
|
+
key: "processScript",
|
|
76
|
+
value: function processScript(script, animationFrame) {
|
|
77
|
+
var scriptDuration = script.duration;
|
|
78
|
+
var len = this.longestScriptTimings.length;
|
|
50
79
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
80
|
+
// Not yet at capacity: append and update min tracking incrementally
|
|
81
|
+
if (len < this.options.limit) {
|
|
82
|
+
var _scriptTiming = this.createScriptTiming(script, animationFrame);
|
|
83
|
+
this.longestScriptTimings[len] = _scriptTiming;
|
|
84
|
+
if (len === 0 || scriptDuration < this.minimumDuration) {
|
|
85
|
+
this.minimumDuration = scriptDuration;
|
|
86
|
+
this.minimumIndex = len;
|
|
54
87
|
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
55
90
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
}
|
|
91
|
+
// At capacity: only do work if we beat the current min
|
|
92
|
+
if (scriptDuration <= this.minimumDuration) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
var scriptTiming = this.createScriptTiming(script, animationFrame);
|
|
96
|
+
|
|
97
|
+
// Replace the current min
|
|
98
|
+
this.longestScriptTimings[this.minimumIndex] = scriptTiming;
|
|
66
99
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
100
|
+
// Find new minimum
|
|
101
|
+
var newMinimumIndex = 0;
|
|
102
|
+
var newMinimumDuration = this.longestScriptTimings[0].duration;
|
|
103
|
+
for (var i = 1; i < this.options.limit; i++) {
|
|
104
|
+
if (this.longestScriptTimings[i].duration < newMinimumDuration) {
|
|
105
|
+
newMinimumIndex = i;
|
|
106
|
+
newMinimumDuration = this.longestScriptTimings[i].duration;
|
|
107
|
+
}
|
|
70
108
|
}
|
|
109
|
+
|
|
110
|
+
// Update the min tracking
|
|
111
|
+
this.minimumIndex = newMinimumIndex;
|
|
112
|
+
this.minimumDuration = newMinimumDuration;
|
|
71
113
|
}
|
|
72
114
|
|
|
73
115
|
/**
|
|
@@ -89,12 +131,12 @@ export var LongAnimationFrameMeasurer = /*#__PURE__*/function () {
|
|
|
89
131
|
}
|
|
90
132
|
|
|
91
133
|
/**
|
|
92
|
-
* Returns the current tracked longest
|
|
134
|
+
* Returns the current tracked longest script timings sorted by duration
|
|
93
135
|
*/
|
|
94
136
|
}, {
|
|
95
137
|
key: "current",
|
|
96
138
|
get: function get() {
|
|
97
|
-
var copy = this.
|
|
139
|
+
var copy = this.longestScriptTimings.slice();
|
|
98
140
|
copy.sort(function (a, b) {
|
|
99
141
|
return b.duration - a.duration;
|
|
100
142
|
});
|
|
@@ -114,5 +156,6 @@ export var LongAnimationFrameMeasurer = /*#__PURE__*/function () {
|
|
|
114
156
|
}();
|
|
115
157
|
|
|
116
158
|
// Based on https://github.com/GoogleChrome/web-vitals/blob/1b872cf5f2159e8ace0e98d55d8eb54fb09adfbe/src/types.ts#L129
|
|
159
|
+
// exported for use in test file
|
|
117
160
|
|
|
118
161
|
// Based on https://github.com/GoogleChrome/web-vitals/blob/1b872cf5f2159e8ace0e98d55d8eb54fb09adfbe/src/types.ts#L129
|
|
@@ -35,20 +35,39 @@ export declare class PeriodTracking {
|
|
|
35
35
|
resume(pauseName: string): void;
|
|
36
36
|
get endResults(): {
|
|
37
37
|
active: {
|
|
38
|
+
count: number;
|
|
39
|
+
duration: number;
|
|
38
40
|
features: Set<string>;
|
|
39
41
|
heavyTasks: Set<string>;
|
|
40
42
|
measurements: {
|
|
41
43
|
[key: string]: Measure;
|
|
42
44
|
};
|
|
43
|
-
duration: number;
|
|
44
|
-
count: number;
|
|
45
45
|
};
|
|
46
46
|
inactive: {
|
|
47
|
+
count: number;
|
|
48
|
+
duration: number;
|
|
47
49
|
features: Set<string>;
|
|
48
50
|
heavyTasks: Set<string>;
|
|
49
51
|
measurements: {
|
|
50
52
|
[key: string]: Measure;
|
|
51
53
|
};
|
|
54
|
+
};
|
|
55
|
+
} | {
|
|
56
|
+
active: {
|
|
57
|
+
features: string[];
|
|
58
|
+
heavyTasks: string[];
|
|
59
|
+
measurements: {
|
|
60
|
+
[key: string]: Measure;
|
|
61
|
+
};
|
|
62
|
+
duration: number;
|
|
63
|
+
count: number;
|
|
64
|
+
};
|
|
65
|
+
inactive: {
|
|
66
|
+
features: string[];
|
|
67
|
+
heavyTasks: string[];
|
|
68
|
+
measurements: {
|
|
69
|
+
[key: string]: Measure;
|
|
70
|
+
};
|
|
52
71
|
duration: number;
|
|
53
72
|
count: number;
|
|
54
73
|
};
|
|
@@ -6,11 +6,14 @@ import { LongAnimationFrameMeasurer } from './session-measurers/LongAnimationFra
|
|
|
6
6
|
* Only intended for internal use.
|
|
7
7
|
*
|
|
8
8
|
* Exported for consumers who may require the type.
|
|
9
|
+
*
|
|
10
|
+
* Note: Events are not reliably fired from mobile browsers (ie. when a browser is closed when not in use)
|
|
9
11
|
*/
|
|
10
12
|
export declare class INSMSession {
|
|
11
13
|
private experienceKey;
|
|
12
14
|
private experienceProperties;
|
|
13
15
|
private startedAt;
|
|
16
|
+
private pageLoadTime;
|
|
14
17
|
insm: INSM;
|
|
15
18
|
private running;
|
|
16
19
|
private addedProperties;
|
|
@@ -18,6 +21,11 @@ export declare class INSMSession {
|
|
|
18
21
|
periodTracking: PeriodTracking;
|
|
19
22
|
longAnimationFrameMeasurer: LongAnimationFrameMeasurer;
|
|
20
23
|
constructor(experienceKey: string, experienceProperties: ExperienceProperties, insm: INSM);
|
|
24
|
+
/**
|
|
25
|
+
* Completes the page load timing. This is called automatically when ending a heavy task
|
|
26
|
+
* with the key 'PageLoad'.
|
|
27
|
+
*/
|
|
28
|
+
completePageLoad(): void;
|
|
21
29
|
updateExperienceKey(experienceKey: string): void;
|
|
22
30
|
/**
|
|
23
31
|
* Adds a feature to the currently running session
|
package/dist/types/insm.d.ts
CHANGED
|
@@ -19,6 +19,9 @@ export declare class INSM {
|
|
|
19
19
|
* Starts a heavy task in the currently running session.
|
|
20
20
|
*
|
|
21
21
|
* This also pauses measurement.
|
|
22
|
+
*
|
|
23
|
+
* For PageLoads using the key 'PageLoad' will mean the heavy task duration
|
|
24
|
+
* is added to the insm session event as pageLoadTime.
|
|
22
25
|
*/
|
|
23
26
|
startHeavyTask(heavyTaskName: string): void;
|
|
24
27
|
/**
|
|
@@ -29,15 +32,19 @@ export declare class INSM {
|
|
|
29
32
|
* Call this when starting a new experience. This is expected to be wired to the product
|
|
30
33
|
* routing solution.
|
|
31
34
|
*
|
|
32
|
-
* It's expected this call will be paired with a `insm.session.startHeavyTask('
|
|
33
|
-
* so that performance degradations linked
|
|
35
|
+
* It's expected this call will be paired with a `insm.session.startHeavyTask('PageLoad')` and
|
|
36
|
+
* subsequent `insm.session.endHeavyTask('PageLoad')` so that performance degradations linked
|
|
37
|
+
* to the page initialisation are excluded from the active interactivity monitoring.
|
|
38
|
+
*
|
|
39
|
+
* Using the key 'PageLoad' is special and will result in the heavy task duration being added to the
|
|
40
|
+
* insm session event as pageLoadTime.
|
|
34
41
|
*
|
|
35
42
|
*
|
|
36
43
|
* ```ts
|
|
37
44
|
* insm.start('edit-page', { initial: true, contentId: '9001' })
|
|
38
|
-
* insm.session.startHeavyTask(''
|
|
45
|
+
* insm.session.startHeavyTask('PageLoad')
|
|
39
46
|
* // ... heavy initialisation work
|
|
40
|
-
* insm.session.endHeavyTask(''
|
|
47
|
+
* insm.session.endHeavyTask('PageLoad')
|
|
41
48
|
* ```
|
|
42
49
|
*/
|
|
43
50
|
start(experienceKey: string, experienceProperties: ExperienceProperties): void;
|