spy-client 2.1.8 → 2.1.9
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/README.md +54 -11
- package/dist/spy-client.esm.js +14 -9
- package/dist/spy-client.iife.js +14 -9
- package/dist/spy-client.iife.min.js +1 -1
- package/dist/spy-client.js +14 -9
- package/dist/spy-client.min.js +1 -1
- package/dist/spy-client.mjs +14 -9
- package/dist/spy-head.js +15 -10
- package/dist/spy-head.min.js +1 -1
- package/package.json +1 -1
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/base.css +0 -224
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/basicSpec.ts.html +0 -740
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/block-navigation.js +0 -79
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/checkSpec.ts.html +0 -479
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/favicon.png +0 -0
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/headSpec.ts.html +0 -695
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/index.html +0 -171
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/markSpec.ts.html +0 -284
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/metricSpec.ts.html +0 -977
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/prettify.css +0 -1
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/prettify.js +0 -2
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
- package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/sorter.js +0 -170
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/base.css +0 -224
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/basicSpec.ts.html +0 -740
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/block-navigation.js +0 -79
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/checkSpec.ts.html +0 -479
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/favicon.png +0 -0
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/headSpec.ts.html +0 -695
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/index.html +0 -171
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/markSpec.ts.html +0 -284
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/metricSpec.ts.html +0 -977
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/prettify.css +0 -1
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/prettify.js +0 -2
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
- package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/sorter.js +0 -170
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/base.css +0 -224
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/basicSpec.ts.html +0 -740
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/block-navigation.js +0 -79
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/checkSpec.ts.html +0 -479
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/favicon.png +0 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/headSpec.ts.html +0 -695
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/index.html +0 -171
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/markSpec.ts.html +0 -284
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/metricSpec.ts.html +0 -977
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/prettify.css +0 -1
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/prettify.js +0 -2
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
- package/coverage/Chrome 96.0.4664.110 (Mac OS 10.15.7)/html/sorter.js +0 -170
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/base.css +0 -224
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/basicSpec.ts.html +0 -740
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/block-navigation.js +0 -79
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/checkSpec.ts.html +0 -479
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/favicon.png +0 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/headSpec.ts.html +0 -695
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/index.html +0 -171
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/markSpec.ts.html +0 -284
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/metricSpec.ts.html +0 -977
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/prettify.css +0 -1
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/prettify.js +0 -2
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
- package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/sorter.js +0 -170
- package/src/head/base.ts +0 -69
- package/src/head/error.ts +0 -118
- package/src/head/observer.ts +0 -40
- package/src/head/readme.md +0 -1
- package/src/head/whitescreen.ts +0 -105
- package/src/lib/data.ts +0 -14
- package/src/lib/huffman.ts +0 -307
- package/src/lib/interface.ts +0 -331
- package/src/lib/spyHeadInterface.ts +0 -40
- package/src/lib/util.ts +0 -101
- package/src/module/fid.ts +0 -56
- package/src/module/layoutShift.ts +0 -71
- package/src/module/lcp.ts +0 -63
- package/src/module/longtask.ts +0 -193
- package/src/module/memory.ts +0 -43
- package/src/module/navigatorInfo.ts +0 -61
- package/src/module/resource.ts +0 -433
- package/src/module/timing.ts +0 -75
- package/src/module/tti.ts +0 -139
- package/src/spy-client-basic.ts +0 -389
- package/src/spy-client.ts +0 -198
- package/src/spy-head.ts +0 -31
- package/src/spy-local-cache.ts +0 -478
- package/src/types/globals.d.ts +0 -93
package/src/lib/util.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file utils
|
|
3
|
-
* @author kaivean
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export function assign(...args: any[]) {
|
|
7
|
-
const __assign = Object.assign || function __assign(t: any) {
|
|
8
|
-
for (let s, i = 1, n = arguments.length; i < n; i++) {
|
|
9
|
-
// eslint-disable-next-line prefer-rest-params
|
|
10
|
-
s = arguments[i];
|
|
11
|
-
for (const p in s) {
|
|
12
|
-
if (Object.prototype.hasOwnProperty.call(s, p)) {
|
|
13
|
-
t[p] = s[p];
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return t;
|
|
18
|
-
};
|
|
19
|
-
return __assign.apply(this, args);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export interface URLINFO {
|
|
23
|
-
protocol: string;
|
|
24
|
-
host: string;
|
|
25
|
-
pathname: string;
|
|
26
|
-
ext: string;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
function getUrlInfoFromURL(url: string): URLINFO | undefined {
|
|
30
|
-
if (URL) {
|
|
31
|
-
const obj = new URL(url);
|
|
32
|
-
if (obj.host !== undefined) {
|
|
33
|
-
return {
|
|
34
|
-
protocol: obj.protocol,
|
|
35
|
-
host: obj.host,
|
|
36
|
-
pathname: obj.pathname,
|
|
37
|
-
ext: '',
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function getUrlInfo(url: string): URLINFO {
|
|
45
|
-
let info = getUrlInfoFromURL(url);
|
|
46
|
-
|
|
47
|
-
if (!info) {
|
|
48
|
-
const parser = document.createElement('a');
|
|
49
|
-
parser.href = url;
|
|
50
|
-
info = {
|
|
51
|
-
protocol: parser.protocol,
|
|
52
|
-
host: parser.host || location.host,
|
|
53
|
-
pathname: parser.pathname,
|
|
54
|
-
ext: '',
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const split = info.pathname.split('.');
|
|
59
|
-
info.ext = split[split.length - 1];
|
|
60
|
-
return info;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function f(n: number): number {
|
|
64
|
-
return +n.toFixed(1);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function getResTiming(t: PerformanceTiming | PerformanceResourceTiming) {
|
|
68
|
-
return {
|
|
69
|
-
wait: f(t.domainLookupStart - ((t as any).navigationStart || t.fetchStart || (t as any).startTime)),
|
|
70
|
-
dns: f(t.domainLookupEnd - t.domainLookupStart),
|
|
71
|
-
connect: f(t.connectEnd - t.connectStart),
|
|
72
|
-
req: f(t.responseStart - t.requestStart),
|
|
73
|
-
res: f(t.responseEnd - t.responseStart),
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
export function getxpath(el: Element | null) {
|
|
79
|
-
if (!el) {
|
|
80
|
-
return {xpath: ''};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const xpath = [];
|
|
84
|
-
while (el && el.nodeType === 1 && el !== el.parentNode) {
|
|
85
|
-
let t = el.tagName.toLowerCase();
|
|
86
|
-
if (el.getAttribute('id')) {
|
|
87
|
-
t += '[#' + el.getAttribute('id') + ']';
|
|
88
|
-
}
|
|
89
|
-
else if (el.classList && el.classList.length) {
|
|
90
|
-
t += '[.' + el.classList[el.classList.length - 1] + ']';
|
|
91
|
-
}
|
|
92
|
-
xpath.push(t);
|
|
93
|
-
if (el === document.body) {
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
el = el.parentNode as HTMLElement; // 修复缺陷检查
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
xpath: xpath.join('<'),
|
|
100
|
-
};
|
|
101
|
-
}
|
package/src/module/fid.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file FID
|
|
3
|
-
* @author kaivean
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {Module, FIDCB} from '../lib/interface';
|
|
7
|
-
|
|
8
|
-
const spyclient = (window as any).__spyHead;
|
|
9
|
-
const entryType = 'first-input';
|
|
10
|
-
|
|
11
|
-
export default class FID implements Module {
|
|
12
|
-
private observer: PerformanceObserver | null = null;
|
|
13
|
-
private cb: FIDCB;
|
|
14
|
-
private finalValue: number;
|
|
15
|
-
constructor() {
|
|
16
|
-
if (!window.PerformanceObserver) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (spyclient && spyclient.entryMap && spyclient.entryMap[entryType]) {
|
|
21
|
-
this.handle(spyclient.entryMap[entryType]);
|
|
22
|
-
}
|
|
23
|
-
try {
|
|
24
|
-
this.observer = new PerformanceObserver(list => {
|
|
25
|
-
this.handle(list.getEntries());
|
|
26
|
-
});
|
|
27
|
-
this.observer.observe({entryTypes: [entryType]});
|
|
28
|
-
}
|
|
29
|
-
catch (e) {}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
listenFID(cb: FIDCB) {
|
|
33
|
-
this.cb = cb;
|
|
34
|
-
this.callCB();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
callCB() {
|
|
38
|
-
if (this.finalValue !== undefined && this.cb) {
|
|
39
|
-
this.cb({fid: this.finalValue});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
destroy() {
|
|
44
|
-
this.observer && this.observer.disconnect();
|
|
45
|
-
this.observer = null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
private handle(entries: PerformanceEntryList) {
|
|
49
|
-
const lastEntry = entries.pop();
|
|
50
|
-
if (lastEntry) {
|
|
51
|
-
this.finalValue = lastEntry.duration;
|
|
52
|
-
this.callCB();
|
|
53
|
-
this.destroy();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file LayoutShift
|
|
3
|
-
* @author kaivean
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {Module, LayoutShiftCB} from '../lib/interface';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const spyclient = (window as any).__spyHead;
|
|
10
|
-
const entryType = 'layout-shift';
|
|
11
|
-
|
|
12
|
-
export default class LayoutShift implements Module {
|
|
13
|
-
private observer: PerformanceObserver | null = null;
|
|
14
|
-
private cb: LayoutShiftCB;
|
|
15
|
-
private value: number;
|
|
16
|
-
private finalValue: number;
|
|
17
|
-
private onceLeave = false;
|
|
18
|
-
constructor() {
|
|
19
|
-
if (!window.PerformanceObserver) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// 先消费之前的
|
|
24
|
-
if (spyclient && spyclient.entryMap && spyclient.entryMap[entryType]) {
|
|
25
|
-
this.handle(spyclient.entryMap[entryType]);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
this.observer = new PerformanceObserver(list => {
|
|
30
|
-
this.handle(list.getEntries());
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
this.observer.observe({entryTypes: [entryType]});
|
|
34
|
-
}
|
|
35
|
-
catch (e) {}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
listenLayoutShift(cb: LayoutShiftCB) {
|
|
39
|
-
this.cb = cb;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
leave() {
|
|
43
|
-
if (!this.onceLeave) {
|
|
44
|
-
this.onceLeave = true;
|
|
45
|
-
this.observer && this.observer.takeRecords && this.observer.takeRecords();
|
|
46
|
-
this.finalValue = this.value;
|
|
47
|
-
this.callCB();
|
|
48
|
-
this.destroy();
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
callCB() {
|
|
53
|
-
if (this.finalValue !== undefined && this.cb) {
|
|
54
|
-
this.cb({layoutShift: this.finalValue});
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
destroy() {
|
|
59
|
-
this.observer && this.observer.disconnect();
|
|
60
|
-
this.observer = null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
private handle(entries: PerformanceEntryList) {
|
|
64
|
-
entries.map(entry => {
|
|
65
|
-
// hadRecentInput 如果过去500毫秒内有用户输入,则返回 true, 刚进入页面内500ms,不会认为是layoutShift
|
|
66
|
-
if (!entry.hadRecentInput) {
|
|
67
|
-
this.value = (this.value || 0) + (entry.value || 0);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
package/src/module/lcp.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file LCP
|
|
3
|
-
* @author kaivean
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {Module, LCPCB} from '../lib/interface';
|
|
7
|
-
import {setData} from '../lib/data';
|
|
8
|
-
|
|
9
|
-
const spyclient = (window as any).__spyHead;
|
|
10
|
-
const entryType = 'largest-contentful-paint';
|
|
11
|
-
|
|
12
|
-
export default class LCP implements Module {
|
|
13
|
-
private observer: PerformanceObserver | null = null;
|
|
14
|
-
private value: number;
|
|
15
|
-
private finalValue: number;
|
|
16
|
-
private cb: LCPCB;
|
|
17
|
-
constructor() {
|
|
18
|
-
if (!window.PerformanceObserver) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
if (spyclient && spyclient.entryMap && spyclient.entryMap[entryType]) {
|
|
22
|
-
this.handle(spyclient.entryMap[entryType]);
|
|
23
|
-
}
|
|
24
|
-
try {
|
|
25
|
-
// 仅在 img,image,svg,video,css url, block element with text nodes
|
|
26
|
-
this.observer = new PerformanceObserver(list => {
|
|
27
|
-
this.handle(list.getEntries());
|
|
28
|
-
});
|
|
29
|
-
this.observer.observe({entryTypes: [entryType]});
|
|
30
|
-
}
|
|
31
|
-
catch (e) {}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
listenLCP(cb: LCPCB) {
|
|
35
|
-
this.cb = cb;
|
|
36
|
-
this.callCB();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
callCB() {
|
|
40
|
-
if (this.finalValue && this.cb) {
|
|
41
|
-
this.cb({lcp: this.finalValue});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
load() {
|
|
46
|
-
this.observer && this.observer.takeRecords && this.observer.takeRecords();
|
|
47
|
-
this.finalValue = this.value;
|
|
48
|
-
setData('lcp', this.value);
|
|
49
|
-
this.callCB();
|
|
50
|
-
this.destroy();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
destroy() {
|
|
54
|
-
this.observer && this.observer.disconnect();
|
|
55
|
-
this.observer = null;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
private handle(entries: PerformanceEntryList) {
|
|
59
|
-
entries.map(entry => {
|
|
60
|
-
this.value = entry.renderTime || entry.loadTime;
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
}
|
package/src/module/longtask.ts
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Longtask
|
|
3
|
-
* @author kaivean
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import {Module, FSPLongtaskCB, LCPLongtaskCB, LoadLongtaskCB, PageLongtaskCB} from '../lib/interface';
|
|
8
|
-
import {getData} from '../lib/data';
|
|
9
|
-
|
|
10
|
-
export interface LongtaskData {
|
|
11
|
-
longtaskTime?: number;
|
|
12
|
-
longtaskRate?: number;
|
|
13
|
-
longtaskNum?: number;
|
|
14
|
-
totalTime?: number;
|
|
15
|
-
longtaskIframeTime?: number;
|
|
16
|
-
longtaskIframeNum?: number;
|
|
17
|
-
longtaskIframeRate?: number;
|
|
18
|
-
iframeLongtasks?: {[propName: string]: number[] | undefined};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const spyclient = window.__spyHead;
|
|
22
|
-
const entryType = 'longtask';
|
|
23
|
-
|
|
24
|
-
export default class Longtask implements Module {
|
|
25
|
-
private lts: PerformanceEntryList = [];
|
|
26
|
-
private observer: PerformanceObserver | null = null;
|
|
27
|
-
private fspCB: FSPLongtaskCB;
|
|
28
|
-
private lcpCB: LCPLongtaskCB;
|
|
29
|
-
private loadCB: LoadLongtaskCB;
|
|
30
|
-
private pageCB: PageLongtaskCB;
|
|
31
|
-
private onceLeave = false;
|
|
32
|
-
constructor() {
|
|
33
|
-
if (spyclient && spyclient.entryMap && spyclient.entryMap[entryType]) {
|
|
34
|
-
this.lts = this.lts.concat(spyclient.entryMap[entryType]);
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
this.observer = new PerformanceObserver(list => {
|
|
38
|
-
this.lts = this.lts.concat(list.getEntries());
|
|
39
|
-
});
|
|
40
|
-
// buffered 兼容性太差
|
|
41
|
-
this.observer.observe({entryTypes: [entryType]});
|
|
42
|
-
}
|
|
43
|
-
catch (e) {}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
check() {
|
|
47
|
-
return window.PerformanceObserver && performance && performance.timing && performance.timing.navigationStart;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
listenFSPLongTask(cb: FSPLongtaskCB) {
|
|
51
|
-
if (!this.check()) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
this.fspCB = cb;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
listenLCPLongTask(cb: LCPLongtaskCB) {
|
|
58
|
-
if (!this.check()) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
this.lcpCB = cb;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
listenLoadLongTask(cb: LoadLongtaskCB) {
|
|
65
|
-
if (!this.check()) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
this.loadCB = cb;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
listenPageLongTask(cb: PageLongtaskCB) {
|
|
72
|
-
if (!this.check()) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
this.pageCB = cb;
|
|
76
|
-
}
|
|
77
|
-
load() {
|
|
78
|
-
if (!this.check()) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const data = this.getStatData(Date.now());
|
|
83
|
-
|
|
84
|
-
// lcp的值存入data模块也是在load期间,这里延迟一会再获取
|
|
85
|
-
setTimeout(() => {
|
|
86
|
-
this.loadCB && this.loadCB({
|
|
87
|
-
loadLongtaskTime: data.time,
|
|
88
|
-
loadTBT: data.tbt,
|
|
89
|
-
loadTotalTime: data.totalTime,
|
|
90
|
-
loadLongtaskRate: data.rate,
|
|
91
|
-
loadLongtaskNum: data.num,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
if (performance.timing && performance.timing.domFirstScreenPaint) {
|
|
95
|
-
const data = this.getStatData(performance.timing.domFirstScreenPaint);
|
|
96
|
-
this.fspCB && this.fspCB({
|
|
97
|
-
fspLongtaskTime: data.time,
|
|
98
|
-
fspTBT: data.tbt,
|
|
99
|
-
fspTotalTime: data.totalTime,
|
|
100
|
-
fspLongtaskRate: data.rate,
|
|
101
|
-
fspLongtaskNum: data.num,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (getData('lcp')) {
|
|
106
|
-
const data = this.getStatData(performance.timing.navigationStart + (getData('lcp') as number));
|
|
107
|
-
this.lcpCB && this.lcpCB({
|
|
108
|
-
lcpLongtaskTime: data.time,
|
|
109
|
-
lcpTBT: data.tbt,
|
|
110
|
-
lcpTotalTime: data.totalTime,
|
|
111
|
-
lcpLongtaskRate: data.rate,
|
|
112
|
-
lcpLongtaskNum: data.num,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
}, 200);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
leave() {
|
|
119
|
-
if (!this.onceLeave) {
|
|
120
|
-
this.onceLeave = true;
|
|
121
|
-
|
|
122
|
-
const data = this.getStatData(Date.now());
|
|
123
|
-
this.pageCB && this.pageCB({
|
|
124
|
-
pageLongtaskTime: data.time,
|
|
125
|
-
pageTBT: data.tbt,
|
|
126
|
-
pageTotalTime: data.totalTime,
|
|
127
|
-
pageLongtaskRate: data.rate,
|
|
128
|
-
pageLongtaskNum: data.num,
|
|
129
|
-
pageIframeLongtaskTime: data.iframeTime,
|
|
130
|
-
pageIframeLongtaskRate: data.iframeRate,
|
|
131
|
-
pageIframeLongtaskNum: data.iframeNum,
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
destroy() {
|
|
138
|
-
this.lts = [];
|
|
139
|
-
this.observer && this.observer.disconnect();
|
|
140
|
-
this.observer = null;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
getStatData(finalTime: number) {
|
|
144
|
-
const navigationStart = performance.timing.navigationStart;
|
|
145
|
-
let time = 0;
|
|
146
|
-
// Total Blocking Time
|
|
147
|
-
let tbt = 0;
|
|
148
|
-
let num = 0;
|
|
149
|
-
let iframeTime = 0;
|
|
150
|
-
let iframeNum = 0;
|
|
151
|
-
let iframeLongtasks = {} as any;
|
|
152
|
-
|
|
153
|
-
for (let index = 0; index < this.lts.length; index++) {
|
|
154
|
-
const item = this.lts[index];
|
|
155
|
-
const duration = item.duration;
|
|
156
|
-
const end = navigationStart + item.startTime + duration;
|
|
157
|
-
|
|
158
|
-
if (end < finalTime) {
|
|
159
|
-
time += duration;
|
|
160
|
-
// 多出来的时间
|
|
161
|
-
tbt += (duration - 50 > 0 ? duration - 50 : 0);
|
|
162
|
-
num++;
|
|
163
|
-
|
|
164
|
-
if (item.attribution && item.attribution[0]) {
|
|
165
|
-
const containerSrc = item.attribution[0].containerSrc;
|
|
166
|
-
if (containerSrc && containerSrc !== location.href) {
|
|
167
|
-
if (!iframeLongtasks[containerSrc]) {
|
|
168
|
-
iframeLongtasks[containerSrc] = [];
|
|
169
|
-
}
|
|
170
|
-
iframeLongtasks[containerSrc].push(duration);
|
|
171
|
-
|
|
172
|
-
iframeTime += duration;
|
|
173
|
-
iframeNum++;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const totalTime = finalTime - navigationStart;
|
|
180
|
-
|
|
181
|
-
return {
|
|
182
|
-
num,
|
|
183
|
-
time,
|
|
184
|
-
tbt,
|
|
185
|
-
totalTime: totalTime,
|
|
186
|
-
rate: 100 * time / totalTime,
|
|
187
|
-
iframeTime,
|
|
188
|
-
iframeNum,
|
|
189
|
-
iframeRate: 100 * iframeTime / totalTime,
|
|
190
|
-
iframeLongtasks,
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
}
|
package/src/module/memory.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Memory
|
|
3
|
-
* @author kaivean
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {Module, MemoryCB} from '../lib/interface';
|
|
7
|
-
|
|
8
|
-
let initMemory: MemoryInfo | null = null;
|
|
9
|
-
if (window.performance && window.performance.memory) {
|
|
10
|
-
initMemory = window.performance.memory;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default class Memory implements Module {
|
|
14
|
-
private cb: MemoryCB;
|
|
15
|
-
private onceLeave = false;
|
|
16
|
-
// constructor() {}
|
|
17
|
-
|
|
18
|
-
listenMemory(cb: MemoryCB) {
|
|
19
|
-
this.cb = cb;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
leave() {
|
|
23
|
-
if (!this.onceLeave && initMemory) {
|
|
24
|
-
this.onceLeave = true;
|
|
25
|
-
|
|
26
|
-
const curMemory = window.performance.memory as MemoryInfo;
|
|
27
|
-
// fix 早期浏览器的memroy api 值不更新的问题,将此情况排除
|
|
28
|
-
if (curMemory.usedJSHeapSize === initMemory.usedJSHeapSize
|
|
29
|
-
&& curMemory.totalJSHeapSize === initMemory.totalJSHeapSize
|
|
30
|
-
) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const memory = window.performance.memory as MemoryInfo;
|
|
35
|
-
this.cb && this.cb({
|
|
36
|
-
usedJSHeapSize: memory.usedJSHeapSize / 1024,
|
|
37
|
-
totalJSHeapSize: memory.totalJSHeapSize / 1024,
|
|
38
|
-
jsHeapSizeLimit: memory.jsHeapSizeLimit / 1024,
|
|
39
|
-
usedJSHeapRate: 100 * memory.usedJSHeapSize / memory.totalJSHeapSize,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file NavigatorInfo
|
|
3
|
-
* @author kaivean
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {Module, NavigatorInfoMetric} from '../lib/interface';
|
|
7
|
-
|
|
8
|
-
export default class NavigatorInfo implements Module {
|
|
9
|
-
// private cb: NavigatorInfoCB;
|
|
10
|
-
|
|
11
|
-
getNavigatorInfo() {
|
|
12
|
-
// this.cb = cb;
|
|
13
|
-
|
|
14
|
-
let ret: NavigatorInfoMetric = {};
|
|
15
|
-
const dataConnection = navigator.connection;
|
|
16
|
-
if (typeof dataConnection === 'object') {
|
|
17
|
-
ret = {
|
|
18
|
-
downlink: dataConnection.downlink, // 网站下载速度 M/s
|
|
19
|
-
effectiveType: dataConnection.effectiveType, // 网络类型
|
|
20
|
-
rtt: dataConnection.rtt, // 网络往返时间 ms
|
|
21
|
-
saveData: !!dataConnection.saveData, // 数据节约模式
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// 内存 G
|
|
26
|
-
if (navigator.deviceMemory) {
|
|
27
|
-
ret.deviceMemory = navigator.deviceMemory;
|
|
28
|
-
}
|
|
29
|
-
// 核数
|
|
30
|
-
if (navigator.hardwareConcurrency) {
|
|
31
|
-
ret.hardwareConcurrency = navigator.deviceMemory;
|
|
32
|
-
}
|
|
33
|
-
return ret;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
load() {}
|
|
37
|
-
|
|
38
|
-
// load() {
|
|
39
|
-
// let ret: NavigatorInfoMetric = {};
|
|
40
|
-
// const dataConnection = navigator.connection;
|
|
41
|
-
// if (typeof dataConnection === 'object') {
|
|
42
|
-
// ret = {
|
|
43
|
-
// downlink: dataConnection.downlink, // 网站下载速度 M/s
|
|
44
|
-
// effectiveType: dataConnection.effectiveType, // 网络类型
|
|
45
|
-
// rtt: dataConnection.rtt, // 网络往返时间 ms
|
|
46
|
-
// saveData: !!dataConnection.saveData, // 数据节约模式
|
|
47
|
-
// };
|
|
48
|
-
// }
|
|
49
|
-
|
|
50
|
-
// // 内存 G
|
|
51
|
-
// if (navigator.deviceMemory) {
|
|
52
|
-
// ret.deviceMemory = navigator.deviceMemory;
|
|
53
|
-
// }
|
|
54
|
-
// // 核数
|
|
55
|
-
// if (navigator.hardwareConcurrency) {
|
|
56
|
-
// ret.hardwareConcurrency = navigator.deviceMemory;
|
|
57
|
-
// }
|
|
58
|
-
|
|
59
|
-
// this.cb && this.cb(ret);
|
|
60
|
-
// }
|
|
61
|
-
}
|