performance-helper 1.0.1 → 1.0.2
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/dist/core/performance.d.ts +15 -0
- package/dist/core/performance.js +76 -6
- package/package.json +1 -1
|
@@ -18,6 +18,12 @@ export declare class PerformanceCollector {
|
|
|
18
18
|
* 采集所有性能指标
|
|
19
19
|
*/
|
|
20
20
|
collect(): PerformanceMetrics;
|
|
21
|
+
/**
|
|
22
|
+
* 采集最终的 LCP 值
|
|
23
|
+
* 从 Performance API 中获取最新的 LCP entry,确保获取的是最终值
|
|
24
|
+
* 这与 Lighthouse 的计算方式一致
|
|
25
|
+
*/
|
|
26
|
+
private collectFinalLCP;
|
|
21
27
|
/**
|
|
22
28
|
* 采集 Navigation Timing 指标
|
|
23
29
|
* 使用 PerformanceNavigationTiming API(新标准)
|
|
@@ -39,6 +45,15 @@ export declare class PerformanceCollector {
|
|
|
39
45
|
private collectWebVitals;
|
|
40
46
|
/**
|
|
41
47
|
* 观察 LCP
|
|
48
|
+
*
|
|
49
|
+
* 根据 Web Vitals 标准和 Lighthouse 的实现:
|
|
50
|
+
* - renderTime 和 loadTime 是相对于 performance.timeOrigin 的
|
|
51
|
+
* - timeOrigin 通常等于 navigation start
|
|
52
|
+
* - 所以 renderTime/loadTime/startTime 已经是相对于 navigation start 的
|
|
53
|
+
*
|
|
54
|
+
* Lighthouse 的计算方式:
|
|
55
|
+
* - 对于图片等资源:优先使用 renderTime,如果没有则使用 loadTime
|
|
56
|
+
* - 对于文本节点:使用 startTime
|
|
42
57
|
*/
|
|
43
58
|
private observeLCP;
|
|
44
59
|
/**
|
package/dist/core/performance.js
CHANGED
|
@@ -23,8 +23,52 @@ export class PerformanceCollector {
|
|
|
23
23
|
*/
|
|
24
24
|
collect() {
|
|
25
25
|
this.collectNavigationTiming();
|
|
26
|
+
// 重新获取最终的 LCP 值,确保与 Lighthouse 一致
|
|
27
|
+
// 因为 LCP 可能在页面加载过程中多次更新,需要在最终时刻获取
|
|
28
|
+
this.collectFinalLCP();
|
|
26
29
|
return { ...this.metrics };
|
|
27
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* 采集最终的 LCP 值
|
|
33
|
+
* 从 Performance API 中获取最新的 LCP entry,确保获取的是最终值
|
|
34
|
+
* 这与 Lighthouse 的计算方式一致
|
|
35
|
+
*/
|
|
36
|
+
collectFinalLCP() {
|
|
37
|
+
if (!window.performance || !window.performance.getEntriesByType) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
// 获取所有 LCP entries,最后一个就是最终的 LCP
|
|
42
|
+
const lcpEntries = window.performance.getEntriesByType('largest-contentful-paint');
|
|
43
|
+
if (lcpEntries.length > 0) {
|
|
44
|
+
const lastEntry = lcpEntries[lcpEntries.length - 1];
|
|
45
|
+
// 使用与 observeLCP 相同的计算逻辑
|
|
46
|
+
let lcpValue;
|
|
47
|
+
if (lastEntry.renderTime !== undefined && lastEntry.renderTime !== null && lastEntry.renderTime > 0) {
|
|
48
|
+
lcpValue = lastEntry.renderTime;
|
|
49
|
+
}
|
|
50
|
+
else if (lastEntry.loadTime !== undefined && lastEntry.loadTime !== null && lastEntry.loadTime > 0) {
|
|
51
|
+
lcpValue = lastEntry.loadTime;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
lcpValue = lastEntry.startTime;
|
|
55
|
+
}
|
|
56
|
+
if (lcpValue !== undefined && lcpValue !== null && lcpValue > 0) {
|
|
57
|
+
this.metrics.lcp = Math.round(lcpValue);
|
|
58
|
+
// 更新 LCP 元素路径
|
|
59
|
+
if (lastEntry.element && lastEntry.element instanceof Element) {
|
|
60
|
+
const elementPath = getElementPath(lastEntry.element);
|
|
61
|
+
if (elementPath) {
|
|
62
|
+
this.metrics.lcpElement = elementPath;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
// 浏览器不支持或出错,使用 observer 中已收集的值
|
|
70
|
+
}
|
|
71
|
+
}
|
|
28
72
|
/**
|
|
29
73
|
* 采集 Navigation Timing 指标
|
|
30
74
|
* 使用 PerformanceNavigationTiming API(新标准)
|
|
@@ -136,6 +180,15 @@ export class PerformanceCollector {
|
|
|
136
180
|
}
|
|
137
181
|
/**
|
|
138
182
|
* 观察 LCP
|
|
183
|
+
*
|
|
184
|
+
* 根据 Web Vitals 标准和 Lighthouse 的实现:
|
|
185
|
+
* - renderTime 和 loadTime 是相对于 performance.timeOrigin 的
|
|
186
|
+
* - timeOrigin 通常等于 navigation start
|
|
187
|
+
* - 所以 renderTime/loadTime/startTime 已经是相对于 navigation start 的
|
|
188
|
+
*
|
|
189
|
+
* Lighthouse 的计算方式:
|
|
190
|
+
* - 对于图片等资源:优先使用 renderTime,如果没有则使用 loadTime
|
|
191
|
+
* - 对于文本节点:使用 startTime
|
|
139
192
|
*/
|
|
140
193
|
observeLCP() {
|
|
141
194
|
if (!('PerformanceObserver' in window)) {
|
|
@@ -143,15 +196,32 @@ export class PerformanceCollector {
|
|
|
143
196
|
}
|
|
144
197
|
try {
|
|
145
198
|
this.lcpObserver = new PerformanceObserver((list) => {
|
|
146
|
-
var _a, _b;
|
|
147
199
|
const entries = list.getEntries();
|
|
148
200
|
const lastEntry = entries[entries.length - 1];
|
|
149
|
-
// LCP
|
|
201
|
+
// LCP 值计算优先级(根据 Web Vitals 标准和 Lighthouse 实现):
|
|
150
202
|
// 1. renderTime - 元素实际渲染到屏幕的时间(最准确,适用于图片等资源)
|
|
151
|
-
// 2.
|
|
152
|
-
// 3.
|
|
153
|
-
|
|
154
|
-
|
|
203
|
+
// 2. loadTime - 资源加载完成时间(适用于图片等资源,如果 renderTime 不可用)
|
|
204
|
+
// 3. startTime - PerformanceEntry 标准属性(总是存在,适用于文本节点等)
|
|
205
|
+
//
|
|
206
|
+
// 注意:这些时间值都是相对于 timeOrigin 的,而 timeOrigin 通常等于 navigation start
|
|
207
|
+
// 所以直接使用这些值即可,与 Lighthouse 的计算方式一致
|
|
208
|
+
let lcpValue;
|
|
209
|
+
if (lastEntry.renderTime !== undefined && lastEntry.renderTime !== null && lastEntry.renderTime > 0) {
|
|
210
|
+
// 优先使用 renderTime(图片等资源的实际渲染时间)
|
|
211
|
+
// 这是 Lighthouse 推荐的方式,最准确
|
|
212
|
+
lcpValue = lastEntry.renderTime;
|
|
213
|
+
}
|
|
214
|
+
else if (lastEntry.loadTime !== undefined && lastEntry.loadTime !== null && lastEntry.loadTime > 0) {
|
|
215
|
+
// 如果没有 renderTime,使用 loadTime(资源加载完成时间)
|
|
216
|
+
lcpValue = lastEntry.loadTime;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
// 最后使用 startTime(文本节点等)
|
|
220
|
+
lcpValue = lastEntry.startTime;
|
|
221
|
+
}
|
|
222
|
+
if (lcpValue !== undefined && lcpValue !== null && lcpValue > 0) {
|
|
223
|
+
// renderTime/loadTime/startTime 已经是相对于 timeOrigin 的
|
|
224
|
+
// 而 timeOrigin 通常等于 navigation start,所以直接使用即可
|
|
155
225
|
this.metrics.lcp = Math.round(lcpValue);
|
|
156
226
|
// 记录LCP元素的路径
|
|
157
227
|
// LargestContentfulPaint entry 的 element 属性指向导致 LCP 的 DOM 元素
|