performance-helper 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +349 -0
- package/dist/core/error.d.ts +35 -0
- package/dist/core/error.js +102 -0
- package/dist/core/performance.d.ts +67 -0
- package/dist/core/performance.js +377 -0
- package/dist/core/reporter.d.ts +38 -0
- package/dist/core/reporter.js +105 -0
- package/dist/core/resource.d.ts +35 -0
- package/dist/core/resource.js +107 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.js +192 -0
- package/dist/types/index.d.ts +134 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/index.d.ts +52 -0
- package/dist/utils/index.js +197 -0
- package/package.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# Performance SDK
|
|
2
|
+
|
|
3
|
+
前端性能监控 SDK,用于采集和上报前端应用的性能指标、资源加载情况和错误信息。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- ✅ **性能指标监控**:FCP、LCP、FID、CLS、TBT、TTFB 等 Web Vitals 指标
|
|
8
|
+
- ✅ **长任务监控**:监控阻塞主线程的长任务,记录详细的归因信息(脚本URL、DOM元素等)
|
|
9
|
+
- ✅ **LCP 元素定位**:自动记录 LCP 元素路径,支持可视化高亮显示
|
|
10
|
+
- ✅ **资源加载监控**:监控所有资源的加载时间和大小
|
|
11
|
+
- ✅ **错误监控**:自动捕获 JavaScript 错误、Promise 错误和资源加载错误
|
|
12
|
+
- ✅ **数据上报**:支持批量上报和立即上报,使用 sendBeacon 确保数据不丢失
|
|
13
|
+
- ✅ **采样率控制**:支持配置采样率,减少数据量
|
|
14
|
+
- ✅ **TypeScript 支持**:完整的类型定义
|
|
15
|
+
|
|
16
|
+
## 安装
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install performance-helper
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 快速开始
|
|
23
|
+
|
|
24
|
+
### 基础使用
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import PerformanceHelper from 'performance-helper';
|
|
28
|
+
|
|
29
|
+
const sdk = new PerformanceHelper({
|
|
30
|
+
reportUrl: 'https://your-api.com/report',
|
|
31
|
+
appId: 'your-app-id',
|
|
32
|
+
userId: 'user-123',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// 初始化 SDK
|
|
36
|
+
sdk.init();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 完整配置
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
const sdk = new PerformanceHelper({
|
|
43
|
+
reportUrl: 'https://your-api.com/report', // 必需:上报地址
|
|
44
|
+
appId: 'your-app-id', // 可选:应用ID
|
|
45
|
+
userId: 'user-123', // 可选:用户ID
|
|
46
|
+
immediate: false, // 可选:是否立即上报,默认 false
|
|
47
|
+
batchInterval: 5000, // 可选:批量上报间隔(毫秒),默认 5000
|
|
48
|
+
monitorResources: true, // 可选:是否监控资源加载,默认 true
|
|
49
|
+
monitorErrors: true, // 可选:是否监控错误,默认 true
|
|
50
|
+
monitorPerformance: true, // 可选:是否监控性能指标,默认 true
|
|
51
|
+
sampleRate: 1, // 可选:采样率 0-1,默认 1
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
sdk.init();
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 使用示例
|
|
58
|
+
|
|
59
|
+
#### 获取性能指标并高亮 LCP 元素
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// 获取性能指标
|
|
63
|
+
const metrics = sdk.getPerformanceMetrics();
|
|
64
|
+
console.log('LCP:', metrics.lcp);
|
|
65
|
+
console.log('TBT:', metrics.tbt);
|
|
66
|
+
console.log('LCP Element:', metrics.lcpElement);
|
|
67
|
+
|
|
68
|
+
// 高亮显示 LCP 元素(用于调试)
|
|
69
|
+
if (metrics.lcpElement) {
|
|
70
|
+
sdk.highlightLCPElement({
|
|
71
|
+
borderColor: '#ff0000',
|
|
72
|
+
borderWidth: '3px',
|
|
73
|
+
backgroundColor: 'rgba(255, 255, 0, 0.2)',
|
|
74
|
+
scrollIntoView: true,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 查看长任务信息
|
|
79
|
+
if (metrics.longTasks && metrics.longTasks.length > 0) {
|
|
80
|
+
metrics.longTasks.forEach((task) => {
|
|
81
|
+
console.log(`长任务: ${task.duration}ms`);
|
|
82
|
+
task.attribution.forEach((attr) => {
|
|
83
|
+
if (attr.scriptURL) {
|
|
84
|
+
console.log(` 脚本: ${attr.scriptURL}`);
|
|
85
|
+
}
|
|
86
|
+
if (attr.elementPath) {
|
|
87
|
+
console.log(` 元素: ${attr.elementPath}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## API
|
|
95
|
+
|
|
96
|
+
### 方法
|
|
97
|
+
|
|
98
|
+
#### `init()`
|
|
99
|
+
初始化 SDK,开始监控。
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
sdk.init();
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### `reportPerformance()`
|
|
106
|
+
手动上报性能指标。
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
sdk.reportPerformance();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### `getPerformanceMetrics()`
|
|
113
|
+
获取当前性能指标。
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const metrics = sdk.getPerformanceMetrics();
|
|
117
|
+
console.log(metrics.fcp, metrics.lcp, metrics.fid);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### `getResources()`
|
|
121
|
+
获取所有资源加载信息。
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const resources = sdk.getResources();
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### `getSlowResources(threshold?)`
|
|
128
|
+
获取慢资源(超过阈值的资源)。
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
const slowResources = sdk.getSlowResources(2000); // 超过 2 秒的资源
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### `getErrors()`
|
|
135
|
+
获取所有错误信息。
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const errors = sdk.getErrors();
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### `reportError(error, context?)`
|
|
142
|
+
手动上报错误。
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
try {
|
|
146
|
+
// some code
|
|
147
|
+
} catch (error) {
|
|
148
|
+
sdk.reportError(error, { customField: 'value' });
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### `reportCustom(type, data)`
|
|
153
|
+
上报自定义数据。
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
sdk.reportCustom('custom', { event: 'click', button: 'submit' });
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### `highlightLCPElement(options?)`
|
|
160
|
+
高亮显示 LCP 元素(用于调试),会在元素周围添加高亮边框并自动滚动到元素位置。
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// 使用默认样式高亮
|
|
164
|
+
sdk.highlightLCPElement();
|
|
165
|
+
|
|
166
|
+
// 自定义样式
|
|
167
|
+
sdk.highlightLCPElement({
|
|
168
|
+
borderColor: '#00ff00',
|
|
169
|
+
borderWidth: '5px',
|
|
170
|
+
backgroundColor: 'rgba(0, 255, 0, 0.3)',
|
|
171
|
+
scrollIntoView: true,
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### `removeLCPHighlight()`
|
|
176
|
+
移除 LCP 元素的高亮效果。
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
sdk.removeLCPHighlight();
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### `destroy()`
|
|
183
|
+
销毁 SDK,清理资源并上报剩余数据。
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
sdk.destroy();
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 性能指标说明
|
|
190
|
+
|
|
191
|
+
### FCP (First Contentful Paint)
|
|
192
|
+
首次内容绘制时间,页面首次渲染文本、图片等内容的时间。
|
|
193
|
+
|
|
194
|
+
### LCP (Largest Contentful Paint)
|
|
195
|
+
最大内容绘制时间,页面最大内容元素渲染完成的时间。
|
|
196
|
+
|
|
197
|
+
### FID (First Input Delay)
|
|
198
|
+
首次输入延迟,用户首次与页面交互到浏览器响应该交互的时间。
|
|
199
|
+
|
|
200
|
+
### CLS (Cumulative Layout Shift)
|
|
201
|
+
累积布局偏移,页面布局稳定性的指标。
|
|
202
|
+
|
|
203
|
+
### TBT (Total Blocking Time)
|
|
204
|
+
总阻塞时间,所有长任务(>50ms)的阻塞时间总和。用于衡量页面交互响应性。
|
|
205
|
+
|
|
206
|
+
### TTFB (Time to First Byte)
|
|
207
|
+
首字节时间,从请求到接收到第一个字节的时间。
|
|
208
|
+
|
|
209
|
+
### LCP Element
|
|
210
|
+
LCP 元素路径,记录导致最大内容绘制的 DOM 元素,使用 CSS 选择器路径格式。
|
|
211
|
+
|
|
212
|
+
### 长任务 (Long Tasks)
|
|
213
|
+
记录所有超过 50ms 的长任务,包含详细的归因信息:
|
|
214
|
+
- 任务类型(script、layout、style、paint、composite 等)
|
|
215
|
+
- 脚本 URL(如果是脚本执行导致的长任务)
|
|
216
|
+
- DOM 元素信息(如果是 DOM 操作导致的长任务)
|
|
217
|
+
- 容器信息(如果是 iframe 等容器中的任务)
|
|
218
|
+
|
|
219
|
+
### 其他指标
|
|
220
|
+
- `dns`: DNS 查询时间
|
|
221
|
+
- `tcp`: TCP 连接时间
|
|
222
|
+
- `request`: 请求响应时间
|
|
223
|
+
- `parse`: DOM 解析时间
|
|
224
|
+
- `domContentLoaded`: DOMContentLoaded 事件时间
|
|
225
|
+
- `load`: Load 事件时间
|
|
226
|
+
|
|
227
|
+
## 数据格式
|
|
228
|
+
|
|
229
|
+
### 性能指标数据
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"type": "performance",
|
|
234
|
+
"data": {
|
|
235
|
+
"fcp": 1200,
|
|
236
|
+
"lcp": 2500,
|
|
237
|
+
"lcpElement": "body > div#app > img.hero-image",
|
|
238
|
+
"fid": 50,
|
|
239
|
+
"cls": 0.1,
|
|
240
|
+
"tbt": 150,
|
|
241
|
+
"ttfb": 300,
|
|
242
|
+
"dns": 20,
|
|
243
|
+
"tcp": 100,
|
|
244
|
+
"request": 200,
|
|
245
|
+
"parse": 500,
|
|
246
|
+
"domContentLoaded": 1500,
|
|
247
|
+
"load": 3006,
|
|
248
|
+
"longTasks": [
|
|
249
|
+
{
|
|
250
|
+
"startTime": 1000,
|
|
251
|
+
"duration": 120,
|
|
252
|
+
"attribution": [
|
|
253
|
+
{
|
|
254
|
+
"taskType": "script",
|
|
255
|
+
"scriptURL": "https://example.com/heavy-script.js",
|
|
256
|
+
"name": "long-task"
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"startTime": 2000,
|
|
262
|
+
"duration": 80,
|
|
263
|
+
"attribution": [
|
|
264
|
+
{
|
|
265
|
+
"taskType": "layout",
|
|
266
|
+
"elementPath": "body > div#app > div.container",
|
|
267
|
+
"elementTag": "div",
|
|
268
|
+
"elementClass": "container"
|
|
269
|
+
}
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
]
|
|
273
|
+
},
|
|
274
|
+
"timestamp": 1234567890,
|
|
275
|
+
"url": "https://example.com",
|
|
276
|
+
"userAgent": "Mozilla/5.0...",
|
|
277
|
+
"appId": "your-app-id",
|
|
278
|
+
"userId": "user-123"
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### 资源数据
|
|
283
|
+
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"type": "resource",
|
|
287
|
+
"data": {
|
|
288
|
+
"name": "https://example.com/image.png",
|
|
289
|
+
"type": "image",
|
|
290
|
+
"duration": 500,
|
|
291
|
+
"size": 102400,
|
|
292
|
+
"startTime": 1000,
|
|
293
|
+
"url": "https://example.com/image.png"
|
|
294
|
+
},
|
|
295
|
+
"timestamp": 1234567890,
|
|
296
|
+
"url": "https://example.com",
|
|
297
|
+
"userAgent": "Mozilla/5.0...",
|
|
298
|
+
"appId": "your-app-id",
|
|
299
|
+
"userId": "user-123"
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### 错误数据
|
|
304
|
+
|
|
305
|
+
```json
|
|
306
|
+
{
|
|
307
|
+
"type": "error",
|
|
308
|
+
"data": {
|
|
309
|
+
"message": "Uncaught TypeError: Cannot read property 'x' of undefined",
|
|
310
|
+
"source": "https://example.com/app.js",
|
|
311
|
+
"lineno": 42,
|
|
312
|
+
"colno": 10,
|
|
313
|
+
"stack": "Error: ...",
|
|
314
|
+
"timestamp": 1234567890,
|
|
315
|
+
"url": "https://example.com",
|
|
316
|
+
"userAgent": "Mozilla/5.0..."
|
|
317
|
+
},
|
|
318
|
+
"timestamp": 1234567890,
|
|
319
|
+
"url": "https://example.com",
|
|
320
|
+
"userAgent": "Mozilla/5.0...",
|
|
321
|
+
"appId": "your-app-id",
|
|
322
|
+
"userId": "user-123"
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## 浏览器兼容性
|
|
327
|
+
|
|
328
|
+
- Chrome 51+
|
|
329
|
+
- Firefox 55+
|
|
330
|
+
- Safari 11+
|
|
331
|
+
- Edge 79+
|
|
332
|
+
|
|
333
|
+
## 开发
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
# 安装依赖
|
|
337
|
+
npm install
|
|
338
|
+
|
|
339
|
+
# 编译
|
|
340
|
+
npm run build
|
|
341
|
+
|
|
342
|
+
# 开发模式(监听文件变化)
|
|
343
|
+
npm run dev
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## License
|
|
347
|
+
|
|
348
|
+
MIT
|
|
349
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ErrorInfo } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* 错误监控器
|
|
4
|
+
*/
|
|
5
|
+
export declare class ErrorMonitor {
|
|
6
|
+
private errors;
|
|
7
|
+
/**
|
|
8
|
+
* 开始监控错误
|
|
9
|
+
*/
|
|
10
|
+
start(): void;
|
|
11
|
+
/**
|
|
12
|
+
* 监控 JavaScript 错误
|
|
13
|
+
*/
|
|
14
|
+
private monitorJSErrors;
|
|
15
|
+
/**
|
|
16
|
+
* 监控 Promise 未捕获的错误
|
|
17
|
+
*/
|
|
18
|
+
private monitorUnhandledRejections;
|
|
19
|
+
/**
|
|
20
|
+
* 监控资源加载错误
|
|
21
|
+
*/
|
|
22
|
+
private monitorResourceErrors;
|
|
23
|
+
/**
|
|
24
|
+
* 错误回调(可被覆盖)
|
|
25
|
+
*/
|
|
26
|
+
private onError;
|
|
27
|
+
/**
|
|
28
|
+
* 获取所有错误
|
|
29
|
+
*/
|
|
30
|
+
getErrors(): ErrorInfo[];
|
|
31
|
+
/**
|
|
32
|
+
* 手动上报错误
|
|
33
|
+
*/
|
|
34
|
+
reportError(error: Error, context?: Record<string, any>): void;
|
|
35
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 错误监控器
|
|
3
|
+
*/
|
|
4
|
+
export class ErrorMonitor {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.errors = [];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 开始监控错误
|
|
10
|
+
*/
|
|
11
|
+
start() {
|
|
12
|
+
// 监控 JavaScript 错误
|
|
13
|
+
this.monitorJSErrors();
|
|
14
|
+
// 监控 Promise 未捕获的错误
|
|
15
|
+
this.monitorUnhandledRejections();
|
|
16
|
+
// 监控资源加载错误
|
|
17
|
+
this.monitorResourceErrors();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 监控 JavaScript 错误
|
|
21
|
+
*/
|
|
22
|
+
monitorJSErrors() {
|
|
23
|
+
window.addEventListener('error', (event) => {
|
|
24
|
+
var _a;
|
|
25
|
+
const errorInfo = {
|
|
26
|
+
message: event.message,
|
|
27
|
+
source: event.filename,
|
|
28
|
+
lineno: event.lineno,
|
|
29
|
+
colno: event.colno,
|
|
30
|
+
stack: (_a = event.error) === null || _a === void 0 ? void 0 : _a.stack,
|
|
31
|
+
timestamp: Date.now(),
|
|
32
|
+
url: window.location.href,
|
|
33
|
+
userAgent: navigator.userAgent,
|
|
34
|
+
};
|
|
35
|
+
this.errors.push(errorInfo);
|
|
36
|
+
this.onError(errorInfo);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 监控 Promise 未捕获的错误
|
|
41
|
+
*/
|
|
42
|
+
monitorUnhandledRejections() {
|
|
43
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
44
|
+
var _a, _b;
|
|
45
|
+
const errorInfo = {
|
|
46
|
+
message: ((_a = event.reason) === null || _a === void 0 ? void 0 : _a.message) || String(event.reason) || 'Unhandled Promise Rejection',
|
|
47
|
+
stack: (_b = event.reason) === null || _b === void 0 ? void 0 : _b.stack,
|
|
48
|
+
timestamp: Date.now(),
|
|
49
|
+
url: window.location.href,
|
|
50
|
+
userAgent: navigator.userAgent,
|
|
51
|
+
};
|
|
52
|
+
this.errors.push(errorInfo);
|
|
53
|
+
this.onError(errorInfo);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 监控资源加载错误
|
|
58
|
+
*/
|
|
59
|
+
monitorResourceErrors() {
|
|
60
|
+
document.addEventListener('error', (event) => {
|
|
61
|
+
const target = event.target;
|
|
62
|
+
if (target && (target.tagName === 'IMG' || target.tagName === 'SCRIPT' || target.tagName === 'LINK')) {
|
|
63
|
+
const errorInfo = {
|
|
64
|
+
message: `Resource load error: ${target.tagName}`,
|
|
65
|
+
source: target.src || target.href || '',
|
|
66
|
+
timestamp: Date.now(),
|
|
67
|
+
url: window.location.href,
|
|
68
|
+
userAgent: navigator.userAgent,
|
|
69
|
+
};
|
|
70
|
+
this.errors.push(errorInfo);
|
|
71
|
+
this.onError(errorInfo);
|
|
72
|
+
}
|
|
73
|
+
}, true);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 错误回调(可被覆盖)
|
|
77
|
+
*/
|
|
78
|
+
onError(errorInfo) {
|
|
79
|
+
// 可以在这里添加自定义错误处理逻辑
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 获取所有错误
|
|
83
|
+
*/
|
|
84
|
+
getErrors() {
|
|
85
|
+
return this.errors;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 手动上报错误
|
|
89
|
+
*/
|
|
90
|
+
reportError(error, context) {
|
|
91
|
+
const errorInfo = {
|
|
92
|
+
message: error.message,
|
|
93
|
+
stack: error.stack,
|
|
94
|
+
timestamp: Date.now(),
|
|
95
|
+
url: window.location.href,
|
|
96
|
+
userAgent: navigator.userAgent,
|
|
97
|
+
...context,
|
|
98
|
+
};
|
|
99
|
+
this.errors.push(errorInfo);
|
|
100
|
+
this.onError(errorInfo);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { PerformanceMetrics } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* 性能指标采集器
|
|
4
|
+
*/
|
|
5
|
+
export declare class PerformanceCollector {
|
|
6
|
+
private metrics;
|
|
7
|
+
private lcpObserver?;
|
|
8
|
+
private fidObserver?;
|
|
9
|
+
private clsObserver?;
|
|
10
|
+
private fcpObserver?;
|
|
11
|
+
private longTaskObserver?;
|
|
12
|
+
private initialized;
|
|
13
|
+
/**
|
|
14
|
+
* 初始化观察器(需要在页面加载前调用)
|
|
15
|
+
*/
|
|
16
|
+
init(): void;
|
|
17
|
+
/**
|
|
18
|
+
* 采集所有性能指标
|
|
19
|
+
*/
|
|
20
|
+
collect(): PerformanceMetrics;
|
|
21
|
+
/**
|
|
22
|
+
* 采集 Navigation Timing 指标
|
|
23
|
+
* 使用 PerformanceNavigationTiming API(新标准)
|
|
24
|
+
*/
|
|
25
|
+
private collectNavigationTiming;
|
|
26
|
+
/**
|
|
27
|
+
* 降级方案:使用旧的 PerformanceTiming API(已废弃,仅作兼容)
|
|
28
|
+
*/
|
|
29
|
+
private collectNavigationTimingLegacy;
|
|
30
|
+
/**
|
|
31
|
+
* 观察 FCP (First Contentful Paint)
|
|
32
|
+
* 使用 PerformanceObserver 更可靠
|
|
33
|
+
*/
|
|
34
|
+
private observeFCP;
|
|
35
|
+
/**
|
|
36
|
+
* 初始化所有性能观察器
|
|
37
|
+
* 在 init() 时调用,用于设置 PerformanceObserver
|
|
38
|
+
*/
|
|
39
|
+
private collectWebVitals;
|
|
40
|
+
/**
|
|
41
|
+
* 观察 LCP
|
|
42
|
+
*/
|
|
43
|
+
private observeLCP;
|
|
44
|
+
/**
|
|
45
|
+
* 观察 FID
|
|
46
|
+
*/
|
|
47
|
+
private observeFID;
|
|
48
|
+
/**
|
|
49
|
+
* 观察 CLS
|
|
50
|
+
*/
|
|
51
|
+
private observeCLS;
|
|
52
|
+
/**
|
|
53
|
+
* 观察长任务并计算 TBT (Total Blocking Time)
|
|
54
|
+
* TBT = 所有长任务(>50ms)的阻塞时间总和
|
|
55
|
+
* 阻塞时间 = 任务持续时间 - 50ms
|
|
56
|
+
*/
|
|
57
|
+
private observeTBT;
|
|
58
|
+
/**
|
|
59
|
+
* 更新 TBT (Total Blocking Time)
|
|
60
|
+
* 从已收集的长任务列表中重新计算 TBT,确保准确性
|
|
61
|
+
*/
|
|
62
|
+
private updateTBT;
|
|
63
|
+
/**
|
|
64
|
+
* 销毁观察器
|
|
65
|
+
*/
|
|
66
|
+
destroy(): void;
|
|
67
|
+
}
|