spy-client 2.1.14 → 2.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.
Files changed (44) hide show
  1. package/.travis.yml +7 -4
  2. package/AGENTS.md +132 -0
  3. package/README.md +29 -18
  4. package/dist/head/base.d.ts +27 -25
  5. package/dist/head/error.d.ts +6 -6
  6. package/dist/head/observer.d.ts +5 -5
  7. package/dist/head/whitescreen.d.ts +6 -6
  8. package/dist/lib/data.d.ts +6 -6
  9. package/dist/lib/huffman.d.ts +9 -9
  10. package/dist/lib/interface.d.ts +209 -209
  11. package/dist/lib/spyHeadInterface.d.ts +36 -28
  12. package/dist/lib/util.d.ts +22 -22
  13. package/dist/module/fid.d.ts +15 -15
  14. package/dist/module/layoutShift.d.ts +18 -18
  15. package/dist/module/lcp.d.ts +17 -17
  16. package/dist/module/longtask.d.ts +46 -46
  17. package/dist/module/memory.d.ts +11 -11
  18. package/dist/module/navigatorInfo.d.ts +9 -9
  19. package/dist/module/resource.d.ts +39 -39
  20. package/dist/module/timing.d.ts +11 -11
  21. package/dist/module/tti.d.ts +19 -19
  22. package/dist/spy-client-basic.d.ts +118 -104
  23. package/dist/spy-client-basic.esm.js +298 -294
  24. package/dist/spy-client-basic.iife.js +298 -294
  25. package/dist/spy-client-basic.iife.min.js +1 -1
  26. package/dist/spy-client-basic.js +298 -294
  27. package/dist/spy-client-basic.min.js +1 -1
  28. package/dist/spy-client-basic.mjs +298 -294
  29. package/dist/spy-client.d.ts +32 -32
  30. package/dist/spy-client.esm.js +1430 -1419
  31. package/dist/spy-client.iife.js +1430 -1419
  32. package/dist/spy-client.iife.min.js +1 -1
  33. package/dist/spy-client.js +1430 -1419
  34. package/dist/spy-client.min.js +1 -1
  35. package/dist/spy-client.mjs +1430 -1419
  36. package/dist/spy-head.d.ts +6 -6
  37. package/dist/spy-head.js +359 -355
  38. package/dist/spy-head.min.js +1 -1
  39. package/dist/spy-local-cache.d.ts +18 -18
  40. package/dist/spy-local-cache.js +718 -711
  41. package/dist/spy-local-cache.min.js +1 -1
  42. package/package.json +26 -73
  43. package/test-results/.last-run.json +4 -0
  44. package/karma.conf.js +0 -111
package/dist/spy-head.js CHANGED
@@ -4,371 +4,375 @@
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.__spyHead = factory());
5
5
  })(this, (function () { 'use strict';
6
6
 
7
- /**
8
- * @file utils
9
- * @author kaivean
10
- */
11
- function getUrlInfoFromURL(url) {
12
- if (URL && url) {
13
- try {
14
- var obj = new URL(url);
15
- if (obj.host !== undefined) {
16
- return {
17
- protocol: obj.protocol,
18
- host: obj.host,
19
- pathname: obj.pathname,
20
- ext: '',
21
- };
22
- }
23
- }
24
- catch (e) {
25
- console.error(e);
26
- }
27
- }
28
- return;
29
- }
30
- function getUrlInfo(url) {
31
- var info = getUrlInfoFromURL(url);
32
- if (!info) {
33
- var parser = document.createElement('a');
34
- parser.href = url;
35
- info = {
36
- protocol: parser.protocol,
37
- host: parser.host || location.host,
38
- pathname: parser.pathname,
39
- ext: '',
40
- };
41
- }
42
- var split = info.pathname.split('.');
43
- info.ext = split[split.length - 1];
44
- return info;
45
- }
46
- function f(n) {
47
- return +n.toFixed(1);
48
- }
49
- function getResTiming(t) {
50
- return {
51
- wait: f(t.domainLookupStart - (t.navigationStart || t.fetchStart || t.startTime)),
52
- dns: f(t.domainLookupEnd - t.domainLookupStart),
53
- connect: f(t.connectEnd - t.connectStart),
54
- req: f(t.responseStart - t.requestStart),
55
- res: f(t.responseEnd - t.responseStart),
56
- };
57
- }
58
- function getxpath(el) {
59
- if (!el) {
60
- return { xpath: '' };
61
- }
62
- var xpath = [];
63
- while (el && el.nodeType === 1 && el !== el.parentNode) {
64
- var t = el.tagName.toLowerCase();
65
- if (el.getAttribute('id')) {
66
- t += '[#' + el.getAttribute('id') + ']';
67
- }
68
- else if (el.classList && el.classList.length) {
69
- t += '[.' + el.classList[el.classList.length - 1] + ']';
70
- }
71
- xpath.push(t);
72
- if (el === document.body) {
73
- break;
74
- }
75
- el = el.parentNode; // 修复缺陷检查
76
- }
77
- return {
78
- xpath: xpath.join('<'),
79
- };
7
+ /**
8
+ * @file utils
9
+ * @author kaivean
10
+ */
11
+ function getUrlInfoFromURL(url) {
12
+ if (URL && url) {
13
+ try {
14
+ var obj = new URL(url);
15
+ if (obj.host !== undefined) {
16
+ return {
17
+ protocol: obj.protocol,
18
+ host: obj.host,
19
+ pathname: obj.pathname,
20
+ ext: '',
21
+ };
22
+ }
23
+ }
24
+ catch (e) {
25
+ console.error(e);
26
+ }
27
+ }
28
+ return;
29
+ }
30
+ function getUrlInfo(url) {
31
+ var info = getUrlInfoFromURL(url);
32
+ if (!info) {
33
+ var parser = document.createElement('a');
34
+ parser.href = url;
35
+ info = {
36
+ protocol: parser.protocol,
37
+ host: parser.host || location.host,
38
+ pathname: parser.pathname,
39
+ ext: '',
40
+ };
41
+ }
42
+ var split = info.pathname.split('.');
43
+ info.ext = split[split.length - 1];
44
+ return info;
45
+ }
46
+ function f(n) {
47
+ return +n.toFixed(1);
48
+ }
49
+ function getResTiming(t) {
50
+ return {
51
+ wait: f(t.domainLookupStart - (t.navigationStart || t.fetchStart || t.startTime)),
52
+ dns: f(t.domainLookupEnd - t.domainLookupStart),
53
+ connect: f(t.connectEnd - t.connectStart),
54
+ req: f(t.responseStart - t.requestStart),
55
+ res: f(t.responseEnd - t.responseStart),
56
+ };
57
+ }
58
+ function getxpath(el) {
59
+ if (!el) {
60
+ return { xpath: '' };
61
+ }
62
+ var xpath = [];
63
+ while (el && el.nodeType === 1 && el !== el.parentNode) {
64
+ var t = el.tagName.toLowerCase();
65
+ if (el.getAttribute('id')) {
66
+ t += '[#' + el.getAttribute('id') + ']';
67
+ }
68
+ else if (el.classList && el.classList.length) {
69
+ t += '[.' + el.classList[el.classList.length - 1] + ']';
70
+ }
71
+ xpath.push(t);
72
+ if (el === document.body) {
73
+ break;
74
+ }
75
+ el = el.parentNode; // 修复缺陷检查
76
+ }
77
+ return {
78
+ xpath: xpath.join('<'),
79
+ };
80
80
  }
81
81
 
82
- /**
83
- * @file 资源、JS、白屏监控的基础
84
- * @author kaivean
85
- */
86
- var spyHead = {
87
- conf: {},
88
- winerrors: [],
89
- errorDestroy: function () { },
90
- observerDestroy: function () { },
91
- entryMap: {},
92
- init: function (conf) {
93
- this.conf = conf;
94
- },
95
- addError: function (obj) {
96
- // 有些错误一下出现很多次,都聚合都一个错误,加上次数
97
- if (this.winerrors.length > 0) {
98
- var lastObj = this.winerrors[this.winerrors.length - 1];
99
- if (obj.info.msg === lastObj.info.msg) {
100
- lastObj.info.count += (lastObj.info.count || 0);
101
- return;
102
- }
103
- }
104
- if (this.winerrors.length < 1000) {
105
- this.winerrors.push(obj);
106
- }
107
- },
108
- send: function (obj, isSend, logServer) {
109
- var conf = this.conf;
110
- obj.type = obj.type || 'except';
111
- obj.pid = conf.pid;
112
- obj.lid = conf.lid;
113
- obj.ts = Date.now();
114
- this.addError(obj);
115
- this.interceptor && this.interceptor(obj);
116
- if (isSend === false) {
117
- return;
118
- }
119
- logServer = logServer || conf.logServer;
120
- var logUrl = "".concat(logServer, "?pid=").concat(obj.pid, "&lid=").concat(obj.lid, "&ts=").concat(obj.ts)
121
- + "&type=".concat(obj.type, "&group=").concat(obj.group, "&info=").concat(encodeURIComponent(JSON.stringify(obj.info)));
122
- if (obj.dim) {
123
- logUrl += '&dim=' + encodeURIComponent(JSON.stringify(obj.dim));
124
- }
125
- var img = new Image();
126
- img.src = logUrl;
127
- img.onload = img.onerror = function () {
128
- img = null;
129
- };
130
- },
82
+ /**
83
+ * @file 资源、JS、白屏监控的基础
84
+ * @author kaivean
85
+ */
86
+ var spyHead = {
87
+ conf: {},
88
+ winerrors: [],
89
+ errorDestroy: function () { },
90
+ observerDestroy: function () { },
91
+ entryMap: {},
92
+ interceptor: undefined,
93
+ init: function (conf) {
94
+ this.conf = conf;
95
+ },
96
+ update: function (conf) {
97
+ this.conf = Object.assign(this.conf, conf || {});
98
+ },
99
+ addError: function (obj) {
100
+ // 有些错误一下出现很多次,都聚合都一个错误,加上次数
101
+ if (this.winerrors.length > 0) {
102
+ var lastObj = this.winerrors[this.winerrors.length - 1];
103
+ if (obj.info.msg === lastObj.info.msg) {
104
+ lastObj.info.count += (lastObj.info.count || 0);
105
+ return;
106
+ }
107
+ }
108
+ if (this.winerrors.length < 1000) {
109
+ this.winerrors.push(obj);
110
+ }
111
+ },
112
+ send: function (obj, isSend, logServer) {
113
+ var conf = this.conf;
114
+ obj.type = obj.type || 'except';
115
+ obj.pid = conf.pid;
116
+ obj.lid = conf.lid;
117
+ obj.ts = Date.now();
118
+ this.addError(obj);
119
+ this.interceptor && this.interceptor(obj);
120
+ if (isSend === false) {
121
+ return;
122
+ }
123
+ logServer = logServer || conf.logServer;
124
+ var logUrl = "".concat(logServer, "?pid=").concat(obj.pid, "&lid=").concat(obj.lid, "&ts=").concat(obj.ts)
125
+ + "&type=".concat(obj.type, "&group=").concat(obj.group, "&info=").concat(encodeURIComponent(JSON.stringify(obj.info)));
126
+ if (obj.dim) {
127
+ logUrl += '&dim=' + encodeURIComponent(JSON.stringify(obj.dim));
128
+ }
129
+ var img = new Image();
130
+ img.src = logUrl;
131
+ img.onload = img.onerror = function () {
132
+ img = null;
133
+ };
134
+ },
131
135
  };
132
136
 
133
- /**
134
- * @file 资源和JS错误监控
135
- * @author kaivean
136
- */
137
- function init$2(conf) {
138
- var resourceError = conf.resourceError || {};
139
- var jsError = conf.jsError || {};
140
- var isSendJserror = Math.random() < (jsError.sample ? jsError.sample : 0);
141
- var isSendResource = Math.random() < (resourceError.sample ? resourceError.sample : 0);
142
- var winerrors = spyHead.winerrors;
143
- var resourceErrorCount = 0;
144
- function spyListenError(event) {
145
- try {
146
- var el = event.target;
147
- var obj = { info: {}, dim: {}, group: '' };
148
- var info = obj.info;
149
- var srcElement = event.srcElement;
150
- // 设备信息
151
- var dataConnection = navigator.connection || {};
152
- info.downlink = dataConnection.downlink; // 网站下载速度 M/s
153
- info.effectiveType = dataConnection.effectiveType; // 网络类型
154
- info.rtt = dataConnection.rtt; // 网络往返时间 ms
155
- info.deviceMemory = navigator.deviceMemory || 0;
156
- info.hardwareConcurrency = navigator.hardwareConcurrency || 0;
157
- // JS错误
158
- if (srcElement === window) {
159
- obj.group = jsError.group;
160
- // 异常信息
161
- // promise错误从reason取
162
- var error = (event.error || event.reason) || {};
163
- // promise错误从error.message取
164
- info.msg = event.message || error.message || '';
165
- info.file = event.filename;
166
- info.ln = event.lineno;
167
- info.col = event.colno;
168
- info.stack = (error.stack || '').split('\n').slice(0, 3).join('\n');
169
- // 针对esl的MODULE_TIMEOUT处理
170
- if (info.msg.indexOf('MODULE_TIMEOUT') !== -1) {
171
- var matches = info.msg.match(/^.*Hang:(.*); Miss:(.*)/);
172
- if (matches && matches[2]) {
173
- info.msg = 'MODULE_TIMEOUT for miss:' + (matches[2]);
174
- }
175
- }
176
- // 历史错误
177
- var historys = [];
178
- for (var index = 0; index < winerrors.length; index++) {
179
- var item = winerrors[index];
180
- var prefix = item.info.count > 1 ? "(".concat(item.info.count, ")") : '';
181
- historys.push(prefix + item.info.msg);
182
- }
183
- info.hisErrors = historys.join('----');
184
- var allow = true;
185
- if (jsError.handler) {
186
- allow = jsError.handler(obj);
187
- }
188
- if (allow !== false) {
189
- spyHead.send(obj, isSendJserror);
190
- }
191
- }
192
- // 资源错误
193
- else {
194
- obj.group = resourceError.group;
195
- obj.dim.type = srcElement.tagName.toLowerCase();
196
- var url = srcElement.src || srcElement.href || '';
197
- // 日志本身失败,要忽略
198
- if (url.indexOf('/mwb2.gif?') > -1) {
199
- return;
200
- }
201
- info.msg = url || 'unknown load eror';
202
- obj.dim.host = getUrlInfo(url).host;
203
- if (el && el.tagName === 'IMG') {
204
- info.xpath = getxpath(el).xpath;
205
- }
206
- if (resourceErrorCount) {
207
- info.hisErrCount = resourceErrorCount;
208
- }
209
- var allow = true;
210
- if (resourceError.handler) {
211
- allow = resourceError.handler(obj);
212
- }
213
- if (allow !== false) {
214
- spyHead.send(obj, isSendResource);
215
- }
216
- resourceErrorCount++;
217
- }
218
- }
219
- catch (e) {
220
- console.error(e);
221
- }
222
- }
223
- window.addEventListener('error', spyListenError, true);
224
- // Promise未处理拒绝监控
225
- window.addEventListener('unhandledrejection', spyListenError, true);
226
- spyHead.errorDestroy = function () {
227
- window.removeEventListener('error', spyListenError, true);
228
- window.removeEventListener('unhandledrejection', spyListenError, true);
229
- spyHead.winerrors = [];
230
- };
137
+ /**
138
+ * @file 资源和JS错误监控
139
+ * @author kaivean
140
+ */
141
+ function init$2(conf) {
142
+ var resourceError = conf.resourceError || {};
143
+ var jsError = conf.jsError || {};
144
+ var isSendJserror = Math.random() < (jsError.sample ? jsError.sample : 0);
145
+ var isSendResource = Math.random() < (resourceError.sample ? resourceError.sample : 0);
146
+ var winerrors = spyHead.winerrors;
147
+ var resourceErrorCount = 0;
148
+ function spyListenError(event) {
149
+ try {
150
+ var el = event.target;
151
+ var obj = { info: {}, dim: {}, group: '' };
152
+ var info = obj.info;
153
+ var srcElement = event.srcElement;
154
+ // 设备信息
155
+ // const dataConnection = navigator.connection || {};
156
+ // info.downlink = dataConnection.downlink; // 网站下载速度 M/s
157
+ // info.effectiveType = dataConnection.effectiveType; // 网络类型
158
+ // info.rtt = dataConnection.rtt; // 网络往返时间 ms
159
+ // info.deviceMemory = navigator.deviceMemory || 0;
160
+ // info.hardwareConcurrency = navigator.hardwareConcurrency || 0;
161
+ // JS错误
162
+ if (srcElement === window) {
163
+ obj.group = jsError.group;
164
+ // 异常信息
165
+ // promise错误从reason取
166
+ var error = (event.error || event.reason) || {};
167
+ // promise错误从error.message取
168
+ info.msg = event.message || error.message || '';
169
+ info.file = event.filename;
170
+ info.ln = event.lineno;
171
+ info.col = event.colno;
172
+ info.stack = (error.stack || '').split('\n').slice(0, 3).join('\n');
173
+ // 针对esl的MODULE_TIMEOUT处理
174
+ if (info.msg.indexOf('MODULE_TIMEOUT') !== -1) {
175
+ var matches = info.msg.match(/^.*Hang:(.*); Miss:(.*)/);
176
+ if (matches && matches[2]) {
177
+ info.msg = 'MODULE_TIMEOUT for miss:' + (matches[2]);
178
+ }
179
+ }
180
+ // 历史错误
181
+ var historys = [];
182
+ for (var index = 0; index < winerrors.length; index++) {
183
+ var item = winerrors[index];
184
+ var prefix = item.info.count > 1 ? "(".concat(item.info.count, ")") : '';
185
+ historys.push(prefix + item.info.msg);
186
+ }
187
+ info.hisErrors = historys.join('----');
188
+ var allow = true;
189
+ if (jsError.handler) {
190
+ allow = jsError.handler(obj);
191
+ }
192
+ if (allow !== false) {
193
+ spyHead.send(obj, isSendJserror);
194
+ }
195
+ }
196
+ // 资源错误
197
+ else {
198
+ obj.group = resourceError.group;
199
+ obj.dim.type = srcElement.tagName.toLowerCase();
200
+ var url = srcElement.src || srcElement.href || '';
201
+ // 日志本身失败,要忽略
202
+ if (url.indexOf('/mwb2.gif?') > -1) {
203
+ return;
204
+ }
205
+ info.msg = url || 'unknown load eror';
206
+ obj.dim.host = getUrlInfo(url).host;
207
+ if (el && el.tagName === 'IMG') {
208
+ info.xpath = getxpath(el).xpath;
209
+ }
210
+ if (resourceErrorCount) {
211
+ info.hisErrCount = resourceErrorCount;
212
+ }
213
+ var allow = true;
214
+ if (resourceError.handler) {
215
+ allow = resourceError.handler(obj);
216
+ }
217
+ if (allow !== false) {
218
+ spyHead.send(obj, isSendResource);
219
+ }
220
+ resourceErrorCount++;
221
+ }
222
+ }
223
+ catch (e) {
224
+ console.error(e);
225
+ }
226
+ }
227
+ window.addEventListener('error', spyListenError, true);
228
+ // Promise未处理拒绝监控
229
+ window.addEventListener('unhandledrejection', spyListenError, true);
230
+ spyHead.errorDestroy = function () {
231
+ window.removeEventListener('error', spyListenError, true);
232
+ window.removeEventListener('unhandledrejection', spyListenError, true);
233
+ spyHead.winerrors = [];
234
+ };
231
235
  }
232
236
 
233
- /**
234
- * @file PerformanceObserver指标采集
235
- * @author kaivean
236
- */
237
- function init$1() {
238
- // Longtask监控
239
- if (window.PerformanceObserver) {
240
- var observer_1 = new window.PerformanceObserver(function spyObserveLongtask(list) {
241
- var entryMap = spyHead.entryMap;
242
- var entries = list.getEntries();
243
- for (var i = 0; i < entries.length; i++) {
244
- var entry = entries[i];
245
- if (!entryMap[entry.entryType]) {
246
- entryMap[entry.entryType] = [];
247
- }
248
- entryMap[entry.entryType].push(entry);
249
- }
250
- });
251
- spyHead.observerDestroy = function () {
252
- observer_1.disconnect();
253
- };
254
- // 在ios下,没有一个类似的监控项是支持的,就抛错,chrome会console warn
255
- try {
256
- observer_1.observe({ entryTypes: [
257
- 'longtask',
258
- 'layout-shift',
259
- 'first-input',
260
- 'largest-contentful-paint',
261
- ] });
262
- }
263
- catch (e) { }
264
- }
237
+ /**
238
+ * @file PerformanceObserver指标采集
239
+ * @author kaivean
240
+ */
241
+ function init$1() {
242
+ // Longtask监控
243
+ if (window.PerformanceObserver) {
244
+ var observer_1 = new window.PerformanceObserver(function spyObserveLongtask(list) {
245
+ var entryMap = spyHead.entryMap;
246
+ var entries = list.getEntries();
247
+ for (var i = 0; i < entries.length; i++) {
248
+ var entry = entries[i];
249
+ if (!entryMap[entry.entryType]) {
250
+ entryMap[entry.entryType] = [];
251
+ }
252
+ entryMap[entry.entryType].push(entry);
253
+ }
254
+ });
255
+ spyHead.observerDestroy = function () {
256
+ observer_1.disconnect();
257
+ };
258
+ // 在ios下,没有一个类似的监控项是支持的,就抛错,chrome会console warn
259
+ try {
260
+ observer_1.observe({ entryTypes: [
261
+ 'longtask',
262
+ 'layout-shift',
263
+ 'first-input',
264
+ 'largest-contentful-paint',
265
+ ] });
266
+ }
267
+ catch (e) { }
268
+ }
265
269
  }
266
270
 
267
- /**
268
- * @file 白屏监控
269
- * @author kaivean
270
- */
271
- function init(conf) {
272
- var whiteScreenError = conf.whiteScreenError || {};
273
- var handler = whiteScreenError.handler;
274
- var selector = whiteScreenError.selector;
275
- var subSelector = whiteScreenError.subSelector;
276
- var timeout = whiteScreenError.timeout || 6000;
277
- var isSend = Math.random() < (whiteScreenError.sample ? whiteScreenError.sample : 0);
278
- // 补充白屏信息:期间的网络时间
279
- function getNetTime() {
280
- if (!window.performance) {
281
- return false;
282
- }
283
- var pf = getResTiming(window.performance.timing);
284
- var netStr = "&wait=".concat(pf.wait)
285
- + "&dns=".concat(pf.dns)
286
- + "&connect=".concat(pf.connect)
287
- + "&requestTime=".concat(pf.req)
288
- + "&resoneTime=".concat(pf.res);
289
- return netStr;
290
- }
291
- // 补充白屏信息:期间发生的JS Error 和 资源 Error
292
- function getHisError() {
293
- if (!(spyHead.winerrors)) {
294
- return false;
295
- }
296
- var errors = spyHead.winerrors;
297
- var historys = [];
298
- for (var i = 0; i < errors.length; i++) {
299
- var stack = (errors[i].info.stack || '').split('\n')[0];
300
- historys.push("(".concat(i, ")").concat(stack || errors[i].info.msg));
301
- }
302
- return historys.join(';;');
303
- }
304
- // 补充白屏信息: 设备信息
305
- function getDeviceInfo() {
306
- var ret = {};
307
- // 设备信息
308
- var dataConnection = navigator.connection || {};
309
- ret.downlink = dataConnection.downlink; // 网站下载速度 M/s
310
- ret.effectiveType = dataConnection.effectiveType; // 网络类型
311
- ret.rtt = dataConnection.rtt; // 网络往返时间 ms
312
- ret.deviceMemory = navigator.deviceMemory || 0;
313
- ret.hardwareConcurrency = navigator.hardwareConcurrency || 0;
314
- return ret;
315
- }
316
- function isWhiteScreen() {
317
- var ele = document.querySelector(selector);
318
- if (!ele) {
319
- return true;
320
- }
321
- var sub = ele.querySelector(subSelector);
322
- if (!sub) {
323
- return true;
324
- }
325
- if (ele.clientHeight < (window.innerHeight * 2 / 3)) {
326
- return true;
327
- }
328
- return false;
329
- }
330
- if (selector) {
331
- setTimeout(function () {
332
- if (isWhiteScreen()) {
333
- var obj = {
334
- group: whiteScreenError.group,
335
- info: {
336
- msg: '',
337
- netTime: getNetTime(),
338
- hisErrors: getHisError(),
339
- deviceInfo: getDeviceInfo(),
340
- },
341
- };
342
- obj.info.msg = 'WhiteScren Error';
343
- var allow = true;
344
- if (handler) {
345
- allow = handler(obj);
346
- }
347
- if (allow !== false && obj.info.msg) {
348
- spyHead && spyHead.send(obj, isSend);
349
- }
350
- }
351
- }, timeout);
352
- }
271
+ /**
272
+ * @file 白屏监控
273
+ * @author kaivean
274
+ */
275
+ function init(conf) {
276
+ var whiteScreenError = conf.whiteScreenError || {};
277
+ var handler = whiteScreenError.handler;
278
+ var selector = whiteScreenError.selector;
279
+ var subSelector = whiteScreenError.subSelector;
280
+ var timeout = whiteScreenError.timeout || 6000;
281
+ var isSend = Math.random() < (whiteScreenError.sample ? whiteScreenError.sample : 0);
282
+ // 补充白屏信息:期间的网络时间
283
+ function getNetTime() {
284
+ if (!window.performance) {
285
+ return false;
286
+ }
287
+ var pf = getResTiming(window.performance.timing);
288
+ var netStr = "&wait=".concat(pf.wait)
289
+ + "&dns=".concat(pf.dns)
290
+ + "&connect=".concat(pf.connect)
291
+ + "&requestTime=".concat(pf.req)
292
+ + "&resoneTime=".concat(pf.res);
293
+ return netStr;
294
+ }
295
+ // 补充白屏信息:期间发生的JS Error 和 资源 Error
296
+ function getHisError() {
297
+ if (!(spyHead.winerrors)) {
298
+ return false;
299
+ }
300
+ var errors = spyHead.winerrors;
301
+ var historys = [];
302
+ for (var i = 0; i < errors.length; i++) {
303
+ var stack = (errors[i].info.stack || '').split('\n')[0];
304
+ historys.push("(".concat(i, ")").concat(stack || errors[i].info.msg));
305
+ }
306
+ return historys.join(';;');
307
+ }
308
+ // 补充白屏信息: 设备信息
309
+ function getDeviceInfo() {
310
+ var ret = {};
311
+ // 设备信息
312
+ var dataConnection = navigator.connection || {};
313
+ ret.downlink = dataConnection.downlink; // 网站下载速度 M/s
314
+ ret.effectiveType = dataConnection.effectiveType; // 网络类型
315
+ ret.rtt = dataConnection.rtt; // 网络往返时间 ms
316
+ ret.deviceMemory = navigator.deviceMemory || 0;
317
+ ret.hardwareConcurrency = navigator.hardwareConcurrency || 0;
318
+ return ret;
319
+ }
320
+ function isWhiteScreen() {
321
+ var ele = document.querySelector(selector);
322
+ if (!ele) {
323
+ return true;
324
+ }
325
+ var sub = ele.querySelector(subSelector);
326
+ if (!sub) {
327
+ return true;
328
+ }
329
+ if (ele.clientHeight < (window.innerHeight * 2 / 3)) {
330
+ return true;
331
+ }
332
+ return false;
333
+ }
334
+ if (selector) {
335
+ setTimeout(function () {
336
+ if (isWhiteScreen()) {
337
+ var obj = {
338
+ group: whiteScreenError.group,
339
+ info: {
340
+ msg: '',
341
+ netTime: getNetTime(),
342
+ hisErrors: getHisError(),
343
+ deviceInfo: getDeviceInfo(),
344
+ },
345
+ };
346
+ obj.info.msg = 'WhiteScren Error';
347
+ var allow = true;
348
+ if (handler) {
349
+ allow = handler(obj);
350
+ }
351
+ if (allow !== false && obj.info.msg) {
352
+ spyHead && spyHead.send(obj, isSend);
353
+ }
354
+ }
355
+ }, timeout);
356
+ }
353
357
  }
354
358
 
355
- /**
356
- * @file SpyClient
357
- * @author kaivean
358
- */
359
- spyHead.init = function (conf) {
360
- if (!conf.logServer) {
361
- conf.logServer = 'https://sp1.baidu.com/5b1ZeDe5KgQFm2e88IuM_a/mwb2.gif';
362
- }
363
- this.conf = conf;
364
- init$2(conf);
365
- init$1();
366
- init(conf);
367
- };
368
- // 兼容全局变量定义的初始化方式
369
- if (window.__spyclientConf) {
370
- spyHead.init(window.__spyclientConf);
371
- }
359
+ /**
360
+ * @file SpyClient
361
+ * @author kaivean
362
+ */
363
+ spyHead.init = function (conf) {
364
+ if (!conf.logServer) {
365
+ conf.logServer = 'https://sp1.baidu.com/5b1ZeDe5KgQFm2e88IuM_a/mwb2.gif';
366
+ }
367
+ this.conf = conf;
368
+ init$2(conf);
369
+ init$1();
370
+ init(conf);
371
+ };
372
+ // 兼容全局变量定义的初始化方式
373
+ if (window.__spyclientConf) {
374
+ spyHead.init(window.__spyclientConf);
375
+ }
372
376
  window.__spyHead = window.__spyHead || spyHead;
373
377
 
374
378
  return spyHead;