spy-client 2.0.7 → 2.1.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/README.md +119 -10
- package/dist/head/base.d.ts +1 -1
- package/dist/lib/huffman.d.ts +9 -0
- package/dist/lib/interface.d.ts +59 -1
- package/dist/lib/util.d.ts +22 -0
- package/dist/module/longtask.d.ts +1 -1
- package/dist/module/resource.d.ts +19 -9
- package/dist/module/tti.d.ts +1 -1
- package/dist/spy-client-basic.esm.js +233 -1167
- package/dist/spy-client-basic.iife.js +237 -1171
- package/dist/spy-client-basic.iife.min.js +1 -1
- package/dist/spy-client-basic.js +238 -1172
- package/dist/spy-client-basic.min.js +1 -1
- package/dist/spy-client-basic.mjs +82 -54
- package/dist/spy-client.d.ts +5 -4
- package/dist/spy-client.esm.js +1393 -5662
- package/dist/spy-client.iife.js +1401 -5670
- package/dist/spy-client.iife.min.js +1 -1
- package/dist/spy-client.js +1402 -5671
- package/dist/spy-client.min.js +1 -1
- package/dist/spy-client.mjs +704 -455
- package/dist/spy-head.js +330 -276
- package/dist/spy-head.min.js +1 -1
- package/dist/spy-local-cache.d.ts +18 -0
- package/dist/spy-local-cache.js +690 -0
- package/dist/spy-local-cache.min.js +1 -0
- package/example/index.html +8 -2
- package/example/local-cache.html +97 -0
- package/example/saveCache.js +41 -0
- package/karma.conf.js +111 -0
- package/package.json +21 -20
- package/src/head/error.ts +14 -15
- package/src/head/whitescreen.ts +8 -5
- package/src/lib/huffman.ts +326 -0
- package/src/lib/interface.ts +70 -1
- package/src/lib/util.ts +101 -0
- package/src/module/resource.ts +226 -129
- package/src/spy-client-basic.ts +8 -7
- package/src/spy-client.ts +15 -6
- package/src/spy-local-cache.ts +385 -0
- package/src/types/globals.d.ts +1 -1
package/src/module/resource.ts
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
// import Debug from 'debug';
|
|
2
|
-
// import { PageApi } from "./pageApi";
|
|
3
|
-
// import WebbInstance from 'webb/instance';
|
|
4
|
-
// import _ from '@searchfe/underscore';
|
|
5
|
-
|
|
6
|
-
// const WEBB_PID = '1_1';
|
|
7
|
-
// const WEBB_TYPE = 'pf_comm';
|
|
8
|
-
// const WEBB_GROUP = 'resource';
|
|
9
|
-
// const debug = Debug('perfcollect:resource');
|
|
10
|
-
|
|
11
|
-
import {Module, ResourceMetric, ResourceCB, ResourceErrorCB, ResType} from '../lib/interface';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// URL拓展
|
|
15
|
-
// 增加后缀名
|
|
16
|
-
interface UrlObj extends URL {
|
|
17
|
-
ext?: string;
|
|
18
|
-
};
|
|
19
1
|
|
|
2
|
+
import {
|
|
3
|
+
Module, ResourceMetric, ResourceCB, ResourceErrorCB, ResType,
|
|
4
|
+
ResOption,
|
|
5
|
+
BigImgOption,
|
|
6
|
+
HttpResOption,
|
|
7
|
+
SlowOption,
|
|
8
|
+
ResourceHostMetric,
|
|
9
|
+
} from '../lib/interface';
|
|
10
|
+
import {getUrlInfo, URLINFO, assign, getResTiming, getxpath} from '../lib/util';
|
|
20
11
|
|
|
21
12
|
// 字体
|
|
22
13
|
// svg使用场景比较灵活,可能作为一种字体格式,也可能当做图片使用
|
|
@@ -32,46 +23,52 @@ enum FontsTypes {
|
|
|
32
23
|
|
|
33
24
|
// 忽略图片
|
|
34
25
|
// 下述图片路径往往是用来进行日志统计,不是正常图片
|
|
35
|
-
|
|
26
|
+
const ignoreDefaultPaths = [
|
|
36
27
|
'/mwb2.gif',
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
function getxpath(el: Element | null) {
|
|
40
|
-
if (!el) {
|
|
41
|
-
return {xpath: ''};
|
|
42
|
-
}
|
|
43
|
-
const xpath = [];
|
|
44
|
-
while (el && el.nodeType === 1 && el !== el.parentNode) {
|
|
45
|
-
xpath.push(el.tagName.toLowerCase());
|
|
28
|
+
];
|
|
46
29
|
|
|
47
|
-
|
|
48
|
-
|
|
30
|
+
function ignorePath(url: string, paths: string[]) {
|
|
31
|
+
for (const path of paths) {
|
|
32
|
+
if (url.indexOf(path) > -1) {
|
|
33
|
+
return true;
|
|
49
34
|
}
|
|
50
|
-
el = el.parentNode as Element; // 修复缺陷检查
|
|
51
35
|
}
|
|
52
|
-
return
|
|
53
|
-
xpath: xpath.join('<'),
|
|
54
|
-
};
|
|
36
|
+
return false;
|
|
55
37
|
}
|
|
56
38
|
|
|
57
39
|
function f(n: number): number {
|
|
58
40
|
return +n.toFixed(1);
|
|
59
41
|
}
|
|
60
42
|
|
|
43
|
+
interface ListItem {
|
|
44
|
+
timing: PerformanceResourceTiming;
|
|
45
|
+
type: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface ListWithHost {
|
|
49
|
+
[host: string]: ListItem[];
|
|
50
|
+
}
|
|
51
|
+
|
|
61
52
|
export default class Resource implements Module {
|
|
62
53
|
private cb: ResourceCB;
|
|
63
54
|
private bigImgCB: ResourceErrorCB;
|
|
64
55
|
private httpResCB: ResourceErrorCB;
|
|
65
|
-
private
|
|
56
|
+
private slowResCB: ResourceErrorCB;
|
|
57
|
+
private resOption: ResOption;
|
|
58
|
+
private bigImgOption: BigImgOption;
|
|
59
|
+
private httpResOption: HttpResOption;
|
|
60
|
+
private slowOption: SlowOption;
|
|
61
|
+
private trigger: string = 'load';
|
|
66
62
|
|
|
67
63
|
private readonly jsList: PerformanceResourceTiming[];
|
|
68
64
|
private readonly cssList: PerformanceResourceTiming[];
|
|
69
65
|
private readonly imgList: PerformanceResourceTiming[];
|
|
70
66
|
private readonly fontList: PerformanceResourceTiming[];
|
|
71
|
-
private readonly imgTnList: PerformanceResourceTiming[];
|
|
72
67
|
|
|
73
|
-
private readonly
|
|
74
|
-
private readonly
|
|
68
|
+
private readonly hostList: ListWithHost;
|
|
69
|
+
private readonly bigImgList: ListWithHost;
|
|
70
|
+
private readonly httpResList: ListWithHost;
|
|
71
|
+
private readonly slowList: ListWithHost;
|
|
75
72
|
|
|
76
73
|
constructor() {
|
|
77
74
|
this.jsList = [];
|
|
@@ -79,113 +76,210 @@ export default class Resource implements Module {
|
|
|
79
76
|
this.imgList = [];
|
|
80
77
|
this.fontList = [];
|
|
81
78
|
|
|
82
|
-
this.
|
|
83
|
-
this.
|
|
79
|
+
this.hostList = {};
|
|
80
|
+
this.bigImgList = {};
|
|
81
|
+
this.httpResList = {};
|
|
82
|
+
this.slowList = {};
|
|
83
|
+
|
|
84
|
+
this.resOption = {ignorePaths: [], trigger: 'load'};
|
|
85
|
+
this.bigImgOption = {ignorePaths: [], maxSize: 150 * 1024, trigger: 'load'};
|
|
86
|
+
this.httpResOption = {ignorePaths: [], trigger: 'load'};
|
|
87
|
+
this.slowOption = {ignorePaths: [], trigger: 'load', threshold: 1000};
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
check() {
|
|
87
91
|
return performance && performance.getEntriesByType;
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
listenResource(cb: ResourceCB) {
|
|
94
|
+
listenResource(cb: ResourceCB, option: ResOption = {}) {
|
|
91
95
|
if (!this.check()) {
|
|
92
96
|
return;
|
|
93
97
|
}
|
|
98
|
+
this.resOption = assign(this.resOption, option);
|
|
99
|
+
this.trigger = this.resOption.trigger as string;
|
|
94
100
|
this.cb = cb;
|
|
95
101
|
}
|
|
96
102
|
|
|
97
|
-
listenBigImg(cb: ResourceErrorCB,
|
|
103
|
+
listenBigImg(cb: ResourceErrorCB, option: BigImgOption = {}) {
|
|
98
104
|
if (!this.check()) {
|
|
99
105
|
return;
|
|
100
106
|
}
|
|
101
|
-
this.
|
|
107
|
+
this.bigImgOption = assign(this.bigImgOption, option);
|
|
108
|
+
this.trigger = this.bigImgOption.trigger as string;
|
|
102
109
|
this.bigImgCB = cb;
|
|
103
110
|
}
|
|
104
111
|
|
|
105
|
-
listenHttpResource(cb: ResourceErrorCB) {
|
|
112
|
+
listenHttpResource(cb: ResourceErrorCB, option: HttpResOption = {}) {
|
|
106
113
|
if (!this.check()) {
|
|
107
114
|
return;
|
|
108
115
|
}
|
|
109
|
-
|
|
116
|
+
this.httpResOption = assign(this.httpResOption, option);
|
|
117
|
+
this.trigger = this.httpResOption.trigger as string;
|
|
110
118
|
this.httpResCB = cb;
|
|
111
119
|
}
|
|
112
120
|
|
|
113
|
-
|
|
121
|
+
listenSlowResource(cb: ResourceErrorCB, option: SlowOption = {}) {
|
|
114
122
|
if (!this.check()) {
|
|
115
123
|
return;
|
|
116
124
|
}
|
|
125
|
+
this.slowOption = assign(this.slowOption, option);
|
|
126
|
+
this.trigger = this.slowOption.trigger as string;
|
|
127
|
+
this.slowResCB = cb;
|
|
128
|
+
}
|
|
117
129
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
130
|
+
report() {
|
|
131
|
+
const metricRes = this.getMetric();
|
|
132
|
+
if (metricRes) {
|
|
133
|
+
const {metric, hostMetric} = metricRes;
|
|
134
|
+
this.cb && this.cb(metric, hostMetric);
|
|
135
|
+
}
|
|
123
136
|
|
|
137
|
+
if (this.bigImgCB) {
|
|
124
138
|
// 发送大图监控数据
|
|
125
|
-
if (window.requestIdleCallback && this.bigImgList.length
|
|
139
|
+
if (typeof window.requestIdleCallback === 'function' && Object.keys(this.bigImgList).length) {
|
|
126
140
|
window.requestIdleCallback(() => {
|
|
127
|
-
for (const
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
for (const host of Object.keys(this.bigImgList)) {
|
|
142
|
+
for (const entry of this.bigImgList[host]) {
|
|
143
|
+
const timing = entry.timing;
|
|
144
|
+
const type = entry.type;
|
|
145
|
+
try {
|
|
146
|
+
const img = document.body.querySelector('img[src="' + timing.name + '"]');
|
|
147
|
+
this.bigImgCB({
|
|
148
|
+
msg: timing.name,
|
|
149
|
+
dur: timing.duration,
|
|
150
|
+
xpath: getxpath(img).xpath,
|
|
151
|
+
host,
|
|
152
|
+
type,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
console.error(e);
|
|
157
|
+
}
|
|
137
158
|
}
|
|
138
159
|
}
|
|
139
160
|
});
|
|
140
161
|
}
|
|
162
|
+
}
|
|
141
163
|
|
|
164
|
+
if (this.httpResCB) {
|
|
142
165
|
// 发送http资源监控数据
|
|
143
|
-
if (window.requestIdleCallback && this.httpResList.length
|
|
166
|
+
if (typeof window.requestIdleCallback === 'function' && Object.keys(this.httpResList).length) {
|
|
144
167
|
window.requestIdleCallback(() => {
|
|
145
|
-
for (const
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
168
|
+
for (const host of Object.keys(this.httpResList)) {
|
|
169
|
+
for (const entry of this.httpResList[host]) {
|
|
170
|
+
const timing = entry.timing;
|
|
171
|
+
const type = entry.type;
|
|
172
|
+
try {
|
|
173
|
+
const img = document.body.querySelector('[src="' + timing.name + '"]');
|
|
174
|
+
this.httpResCB({
|
|
175
|
+
msg: timing.name,
|
|
176
|
+
dur: timing.duration,
|
|
177
|
+
xpath: getxpath(img).xpath,
|
|
178
|
+
host,
|
|
179
|
+
type,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
catch (e) {
|
|
183
|
+
console.error(e);
|
|
184
|
+
}
|
|
152
185
|
}
|
|
153
|
-
|
|
154
|
-
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (this.slowResCB) {
|
|
192
|
+
// 发送慢资源监控数据
|
|
193
|
+
if (typeof window.requestIdleCallback === 'function' && Object.keys(this.slowList).length) {
|
|
194
|
+
window.requestIdleCallback(() => {
|
|
195
|
+
for (const host of Object.keys(this.slowList)) {
|
|
196
|
+
for (const entry of this.slowList[host]) {
|
|
197
|
+
const timing = entry.timing;
|
|
198
|
+
const type = entry.type;
|
|
199
|
+
try {
|
|
200
|
+
const img = document.body.querySelector('[src="' + timing.name + '"]');
|
|
201
|
+
|
|
202
|
+
const info = getResTiming(timing);
|
|
203
|
+
|
|
204
|
+
this.slowResCB({
|
|
205
|
+
...info,
|
|
206
|
+
dur: timing.duration,
|
|
207
|
+
msg: timing.name,
|
|
208
|
+
xpath: getxpath(img).xpath,
|
|
209
|
+
host,
|
|
210
|
+
type,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
catch (e) {
|
|
214
|
+
console.error(e);
|
|
215
|
+
}
|
|
155
216
|
}
|
|
156
217
|
}
|
|
157
218
|
});
|
|
158
219
|
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
load() {
|
|
224
|
+
if (this.trigger !== 'load') {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (!this.check()) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
setTimeout(() => {
|
|
232
|
+
this.report();
|
|
159
233
|
}, 500);
|
|
160
234
|
}
|
|
161
235
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const split = urlObj.pathname.split('.');
|
|
166
|
-
urlObj.ext = split[split.length - 1];
|
|
167
|
-
return urlObj;
|
|
236
|
+
leave() {
|
|
237
|
+
if (this.trigger !== 'leave') {
|
|
238
|
+
return;
|
|
168
239
|
}
|
|
169
|
-
|
|
170
|
-
|
|
240
|
+
this.report();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private push(type: string, list: any, timing: PerformanceResourceTiming, urlInfo: URLINFO) {
|
|
244
|
+
if (!ignorePath(urlInfo.pathname, this.resOption.ignorePaths || [])) {
|
|
245
|
+
list.push(timing);
|
|
246
|
+
this.pushWithHost(type, this.hostList, timing, urlInfo);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!ignorePath(urlInfo.pathname, this.slowOption.ignorePaths || [])) {
|
|
250
|
+
if (timing.duration > (this.slowOption.threshold as number)) {
|
|
251
|
+
this.pushWithHost(type, this.slowList, timing, urlInfo);
|
|
252
|
+
}
|
|
171
253
|
}
|
|
254
|
+
|
|
172
255
|
}
|
|
173
256
|
|
|
174
|
-
private
|
|
175
|
-
|
|
176
|
-
|
|
257
|
+
private pushWithHost(type: string, list: any, timing: PerformanceResourceTiming, urlInfo: URLINFO) {
|
|
258
|
+
const host = urlInfo.host;
|
|
259
|
+
if (!list[host]) {
|
|
260
|
+
list[host] = [] as ListItem[];
|
|
261
|
+
}
|
|
262
|
+
list[host].push({
|
|
263
|
+
timing,
|
|
264
|
+
type,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private collectHttpResInHttps(type: string, timing: PerformanceResourceTiming, urlInfo: URLINFO) {
|
|
269
|
+
if (location.protocol === 'https:'
|
|
270
|
+
&& timing.name.indexOf('http://') === 0
|
|
271
|
+
&& !ignorePath(urlInfo.pathname, this.httpResOption.ignorePaths || [])
|
|
272
|
+
) {
|
|
273
|
+
this.pushWithHost(type, this.httpResList, timing, urlInfo);
|
|
177
274
|
}
|
|
178
275
|
}
|
|
179
276
|
|
|
180
277
|
// 有些jsonp也属于script,这里只统计js后缀的文件
|
|
181
|
-
private addScript(timing: PerformanceResourceTiming) {
|
|
182
|
-
|
|
183
|
-
if (ext === 'js') {
|
|
278
|
+
private addScript(timing: PerformanceResourceTiming, urlInfo: URLINFO) {
|
|
279
|
+
if (urlInfo.ext === 'js') {
|
|
184
280
|
if (timing.decodedBodySize !== 0) {
|
|
185
|
-
this.
|
|
281
|
+
this.push('js', this.jsList, timing, urlInfo);
|
|
186
282
|
}
|
|
187
|
-
|
|
188
|
-
this.collectHttpResInHttps(timing);
|
|
189
283
|
}
|
|
190
284
|
}
|
|
191
285
|
|
|
@@ -194,70 +288,67 @@ export default class Resource implements Module {
|
|
|
194
288
|
// 2、加载背景图(图片不容易区分,有的没有明确后缀名)
|
|
195
289
|
// 3、光标文件(后缀为.cur,这里也划分为图片)
|
|
196
290
|
// (svg当做图片,前述已说明)
|
|
197
|
-
private
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
this.fontList.push(timing);
|
|
291
|
+
private addResFromCss(timing: PerformanceResourceTiming, urlInfo: URLINFO) {
|
|
292
|
+
if (urlInfo.ext && FontsTypes.hasOwnProperty(urlInfo.ext)) {
|
|
293
|
+
this.push('font', this.fontList, timing, urlInfo);
|
|
201
294
|
}
|
|
202
295
|
else {
|
|
203
|
-
this.
|
|
296
|
+
this.addImg(timing, urlInfo);
|
|
204
297
|
}
|
|
205
298
|
}
|
|
206
299
|
|
|
207
300
|
// link一般加载css资源
|
|
208
301
|
// 也可以通过preload可以预下载一些资源
|
|
209
302
|
// 这里只统计js类型的preload
|
|
210
|
-
private addLink(timing: PerformanceResourceTiming) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
this.cssList.push(timing);
|
|
303
|
+
private addLink(timing: PerformanceResourceTiming, urlInfo: URLINFO) {
|
|
304
|
+
if (urlInfo.ext === 'css') {
|
|
305
|
+
this.push('css', this.cssList, timing, urlInfo);
|
|
214
306
|
}
|
|
215
307
|
// preload as script
|
|
216
|
-
else if (ext === 'js') {
|
|
217
|
-
this.
|
|
308
|
+
else if (urlInfo.ext === 'js') {
|
|
309
|
+
this.push('js', this.jsList, timing, urlInfo);
|
|
218
310
|
}
|
|
219
311
|
}
|
|
220
312
|
|
|
221
|
-
private addImg(timing: PerformanceResourceTiming) {
|
|
222
|
-
|
|
223
|
-
if (!IgnoreImgPath.hasOwnProperty(pathname)) {
|
|
224
|
-
this.imgList.push(timing);
|
|
225
|
-
|
|
226
|
-
// 识别出处理webp的url
|
|
227
|
-
if (timing.name.indexOf('fm=') > -1 && timing.name.indexOf('webpstat=1') > -1) {
|
|
228
|
-
this.imgTnList.push(timing);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// 大于102400=100K的采集
|
|
232
|
-
if (timing.decodedBodySize > this.maxImgSize) {
|
|
233
|
-
this.bigImgList.push(timing);
|
|
234
|
-
}
|
|
313
|
+
private addImg(timing: PerformanceResourceTiming, urlInfo: URLINFO) {
|
|
314
|
+
this.push('img', this.imgList, timing, urlInfo);
|
|
235
315
|
|
|
236
|
-
|
|
316
|
+
// 大于指定size的图片采集
|
|
317
|
+
if (
|
|
318
|
+
timing.decodedBodySize > (this.bigImgOption.maxSize || 0)
|
|
319
|
+
&& !ignorePath(urlInfo.pathname, this.bigImgOption.ignorePaths || [])
|
|
320
|
+
) {
|
|
321
|
+
this.pushWithHost('img', this.bigImgList, timing, urlInfo);
|
|
237
322
|
}
|
|
238
323
|
}
|
|
239
324
|
|
|
240
325
|
private handleTimings(list: PerformanceEntry[]) {
|
|
241
326
|
const len = list.length;
|
|
242
327
|
for (let i = 0; i < len; i++) {
|
|
328
|
+
const timing = list[i] as PerformanceResourceTiming;
|
|
329
|
+
const urlInfo = getUrlInfo(timing.name);
|
|
330
|
+
|
|
331
|
+
if (ignorePath(urlInfo.pathname, ignoreDefaultPaths)) {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
243
334
|
switch ((list[i] as any).initiatorType) {
|
|
244
335
|
case 'script':
|
|
245
|
-
this.addScript(
|
|
336
|
+
this.addScript(timing, urlInfo);
|
|
246
337
|
break;
|
|
247
338
|
case 'css':
|
|
248
|
-
this.
|
|
339
|
+
this.addResFromCss(timing, urlInfo);
|
|
249
340
|
break;
|
|
250
341
|
case 'img':
|
|
251
|
-
this.addImg(
|
|
342
|
+
this.addImg(timing, urlInfo);
|
|
252
343
|
break;
|
|
253
344
|
case 'link':
|
|
254
|
-
this.addLink(
|
|
345
|
+
this.addLink(timing, urlInfo);
|
|
255
346
|
break;
|
|
256
347
|
case 'audio':
|
|
257
|
-
this.collectHttpResInHttps(
|
|
348
|
+
this.collectHttpResInHttps('audio', timing, urlInfo);
|
|
258
349
|
break;
|
|
259
350
|
case 'video':
|
|
260
|
-
this.collectHttpResInHttps(
|
|
351
|
+
this.collectHttpResInHttps('video', timing, urlInfo);
|
|
261
352
|
break;
|
|
262
353
|
default:
|
|
263
354
|
break;
|
|
@@ -265,7 +356,7 @@ export default class Resource implements Module {
|
|
|
265
356
|
}
|
|
266
357
|
}
|
|
267
358
|
|
|
268
|
-
private getNumAndSize(type:
|
|
359
|
+
private getNumAndSize(type: string, list: PerformanceResourceTiming[]) {
|
|
269
360
|
const obj: any = {};
|
|
270
361
|
const num = type + 'Num';
|
|
271
362
|
const size = type + 'Size';
|
|
@@ -276,7 +367,7 @@ export default class Resource implements Module {
|
|
|
276
367
|
obj[size] = 0;
|
|
277
368
|
obj[transferSize] = 0;
|
|
278
369
|
let totalDurationTime = 0;
|
|
279
|
-
|
|
370
|
+
list.forEach((timing: PerformanceResourceTiming) => {
|
|
280
371
|
obj[num]++;
|
|
281
372
|
obj[size] += (timing.decodedBodySize / 1024);
|
|
282
373
|
obj[transferSize] += (timing.transferSize / 1024);
|
|
@@ -295,7 +386,7 @@ export default class Resource implements Module {
|
|
|
295
386
|
return obj;
|
|
296
387
|
}
|
|
297
388
|
|
|
298
|
-
private getMetric(): ResourceMetric | undefined {
|
|
389
|
+
private getMetric(): {metric: ResourceMetric, hostMetric: ResourceHostMetric} | undefined {
|
|
299
390
|
// 原来代码
|
|
300
391
|
const {0: mainPageTiming} = performance.getEntriesByType('navigation');
|
|
301
392
|
const resourceTimings = performance.getEntriesByType('resource');
|
|
@@ -304,10 +395,10 @@ export default class Resource implements Module {
|
|
|
304
395
|
this.handleTimings(resourceTimings);
|
|
305
396
|
|
|
306
397
|
let metric: ResourceMetric = {
|
|
307
|
-
...this.getNumAndSize(ResType.JS),
|
|
308
|
-
...this.getNumAndSize(ResType.CSS),
|
|
309
|
-
...this.getNumAndSize(ResType.IMG),
|
|
310
|
-
...this.getNumAndSize(ResType.FONT),
|
|
398
|
+
...this.getNumAndSize(ResType.JS, this.jsList),
|
|
399
|
+
...this.getNumAndSize(ResType.CSS, this.cssList),
|
|
400
|
+
...this.getNumAndSize(ResType.IMG, this.imgList),
|
|
401
|
+
...this.getNumAndSize(ResType.FONT, this.fontList),
|
|
311
402
|
};
|
|
312
403
|
|
|
313
404
|
// 主文档大小
|
|
@@ -329,7 +420,13 @@ export default class Resource implements Module {
|
|
|
329
420
|
+ metric.imgTransferSize
|
|
330
421
|
+ metric.fontTransferSize);
|
|
331
422
|
|
|
332
|
-
|
|
423
|
+
const hostMetric: ResourceHostMetric = {};
|
|
424
|
+
for (const host of Object.keys(this.hostList)) {
|
|
425
|
+
const timings = this.hostList[host].map(item => item.timing);
|
|
426
|
+
hostMetric[host] = this.getNumAndSize('host', timings);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return {metric, hostMetric};
|
|
333
430
|
}
|
|
334
431
|
return;
|
|
335
432
|
}
|