network-speed-js 1.0.2 → 1.0.3
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 +48 -10
- package/dist/core/speed-tester.d.ts +8 -0
- package/dist/core/speed-tester.d.ts.map +1 -1
- package/dist/core/types.d.ts +10 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/network-speed-js.js +68 -50
- package/dist/network-speed-js.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -172,6 +172,20 @@ new NetworkSpeedSDK(options?: SpeedTestOptions)
|
|
|
172
172
|
| `autoDetect` | `boolean` | `true` | 是否自动检测内外网 |
|
|
173
173
|
| `timeout` | `number` | `10000` | 超时时间 (ms) |
|
|
174
174
|
| `thresholds` | `object` | `{fast: 10, medium: 2}` | 网速评估阈值 (Mbps) |
|
|
175
|
+
| `resourceType` | `'image' \| 'fetch'` | `'image'` | 资源类型(见下方说明) |
|
|
176
|
+
|
|
177
|
+
**resourceType 说明:**
|
|
178
|
+
|
|
179
|
+
- `'image'`(默认):使用 Image 对象加载
|
|
180
|
+
- ✅ 不受跨域限制
|
|
181
|
+
- ✅ 适用于图片资源(.jpg、.png、.webp 等)
|
|
182
|
+
- ✅ 无需服务器配置 CORS
|
|
183
|
+
- ⚠️ 仅支持图片格式
|
|
184
|
+
|
|
185
|
+
- `'fetch'`:使用 fetch API 加载
|
|
186
|
+
- ✅ 支持任意类型资源(.bin、.json、.txt 等)
|
|
187
|
+
- ⚠️ 需要服务器配置 CORS
|
|
188
|
+
- ⚠️ 受跨域限制
|
|
175
189
|
|
|
176
190
|
#### 方法
|
|
177
191
|
|
|
@@ -265,12 +279,34 @@ interface ResourceSpeedInfo {
|
|
|
265
279
|
|
|
266
280
|
## 💡 使用示例
|
|
267
281
|
|
|
268
|
-
### 1.
|
|
282
|
+
### 1. 使用图片资源测速(默认,推荐)
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
const sdk = new NetworkSpeedSDK({
|
|
286
|
+
internetUrl: 'https://cdn.example.com/test-image.jpg',
|
|
287
|
+
// resourceType: 'image', // 默认值,可省略
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
const result = await sdk.test();
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### 2. 使用非图片资源测速(需要 CORS)
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
const sdk = new NetworkSpeedSDK({
|
|
297
|
+
internetUrl: 'https://cdn.example.com/test-file.bin',
|
|
298
|
+
resourceType: 'fetch', // 使用 fetch API
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const result = await sdk.test();
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 3. 内外网自动检测
|
|
269
305
|
|
|
270
306
|
```typescript
|
|
271
307
|
const sdk = new NetworkSpeedSDK({
|
|
272
|
-
intranetUrl: 'https://internal-cdn.company.com/test.
|
|
273
|
-
internetUrl: 'https://public-cdn.example.com/test.
|
|
308
|
+
intranetUrl: 'https://internal-cdn.company.com/test.jpg',
|
|
309
|
+
internetUrl: 'https://public-cdn.example.com/test.jpg',
|
|
274
310
|
autoDetect: true,
|
|
275
311
|
});
|
|
276
312
|
|
|
@@ -278,7 +314,7 @@ const result = await sdk.test();
|
|
|
278
314
|
console.log(result.isIntranet ? '内网环境' : '外网环境');
|
|
279
315
|
```
|
|
280
316
|
|
|
281
|
-
###
|
|
317
|
+
### 4. 首屏加载质量评估
|
|
282
318
|
|
|
283
319
|
```typescript
|
|
284
320
|
const result = await sdk.test();
|
|
@@ -489,16 +525,18 @@ dd if=/dev/urandom of=speed-test.bin bs=1024 count=500
|
|
|
489
525
|
|
|
490
526
|
**测速文件建议:**
|
|
491
527
|
- 文件大小:200KB ~ 1MB
|
|
492
|
-
-
|
|
528
|
+
- 文件类型:
|
|
529
|
+
- 图片格式(推荐):.jpg、.png、.webp(使用默认 `resourceType: 'image'`)
|
|
530
|
+
- 其他格式:.bin、.json、.txt(需设置 `resourceType: 'fetch'` 并配置 CORS)
|
|
493
531
|
- 禁用缓存
|
|
494
|
-
- 启用 CORS
|
|
532
|
+
- 启用 CORS(仅 fetch 模式需要)
|
|
495
533
|
- 使用 CDN 分发
|
|
496
534
|
|
|
497
535
|
**支持的资源类型:**
|
|
498
|
-
- ✅
|
|
499
|
-
- ✅
|
|
500
|
-
- ✅ 文本文件(.txt、.json
|
|
501
|
-
- ✅ 任何可通过 HTTP 访问的资源
|
|
536
|
+
- ✅ 图片文件(.jpg、.png、.webp)- 默认模式,无需 CORS
|
|
537
|
+
- ✅ 二进制文件(.bin)- 需要 fetch 模式和 CORS
|
|
538
|
+
- ✅ 文本文件(.txt、.json)- 需要 fetch 模式和 CORS
|
|
539
|
+
- ✅ 任何可通过 HTTP 访问的资源 - 需要 fetch 模式和 CORS
|
|
502
540
|
|
|
503
541
|
### 配置项详解
|
|
504
542
|
|
|
@@ -18,6 +18,14 @@ export declare class SpeedTester {
|
|
|
18
18
|
* 测试单个URL
|
|
19
19
|
*/
|
|
20
20
|
private testSingleUrl;
|
|
21
|
+
/**
|
|
22
|
+
* 使用 Image 对象加载资源(默认方式,不受跨域限制)
|
|
23
|
+
*/
|
|
24
|
+
private loadWithImage;
|
|
25
|
+
/**
|
|
26
|
+
* 使用 fetch API 加载资源(需要 CORS 支持)
|
|
27
|
+
*/
|
|
28
|
+
private loadWithFetch;
|
|
21
29
|
/**
|
|
22
30
|
* 监听特定资源的性能数据
|
|
23
31
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speed-tester.d.ts","sourceRoot":"","sources":["../../src/core/speed-tester.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,SAAS,CAAC;AAGjB;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,QAAQ,CAAoC;gBAExC,OAAO,GAAE,gBAAqB;
|
|
1
|
+
{"version":3,"file":"speed-tester.d.ts","sourceRoot":"","sources":["../../src/core/speed-tester.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,SAAS,CAAC;AAGjB;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,QAAQ,CAAoC;gBAExC,OAAO,GAAE,gBAAqB;IAW1C;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC;IAQtC;;OAEG;YACW,kBAAkB;IAehC;;OAEG;IACH,OAAO,CAAC,aAAa;IA0DrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAqBrB;;OAEG;IACH,OAAO,CAAC,aAAa;IA4BrB;;OAEG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,wBAAwB,GAAG,MAAM,IAAI;IAkBnF;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI;IAIvD;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -32,6 +32,10 @@ export interface ResourceSpeedInfo {
|
|
|
32
32
|
/** 传输大小 (bytes) */
|
|
33
33
|
transferSize: number;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* 资源类型
|
|
37
|
+
*/
|
|
38
|
+
export type ResourceType = 'image' | 'fetch';
|
|
35
39
|
/**
|
|
36
40
|
* SDK配置选项
|
|
37
41
|
*/
|
|
@@ -49,6 +53,12 @@ export interface SpeedTestOptions {
|
|
|
49
53
|
fast: number;
|
|
50
54
|
medium: number;
|
|
51
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* 资源类型
|
|
58
|
+
* - 'image': 使用 Image 对象加载(默认,不受跨域限制,适用于图片资源)
|
|
59
|
+
* - 'fetch': 使用 fetch API 加载(需要服务器支持 CORS,适用于任意资源)
|
|
60
|
+
*/
|
|
61
|
+
resourceType?: ResourceType;
|
|
52
62
|
}
|
|
53
63
|
/**
|
|
54
64
|
* Performance Observer 回调参数
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kBAAkB;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,WAAW,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IACpD,YAAY;IACZ,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW;IACX,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oBAAoB;IACpB,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kBAAkB;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,WAAW,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IACpD,YAAY;IACZ,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW;IACX,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,OAAO,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oBAAoB;IACpB,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF;;;;OAIG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,CAAC,KAAK,EAAE,yBAAyB,GAAG,IAAI,CAAC;CAC1C"}
|
package/dist/network-speed-js.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
function
|
|
1
|
+
function l(t) {
|
|
2
2
|
const e = t.responseEnd - t.responseStart;
|
|
3
3
|
if (e <= 0 || t.transferSize === 0)
|
|
4
4
|
return null;
|
|
5
|
-
const
|
|
5
|
+
const s = t.transferSize * 8 / e / 1e3, n = t.transferSize / e;
|
|
6
6
|
return {
|
|
7
7
|
name: t.name,
|
|
8
|
-
speedMbps: Number(
|
|
8
|
+
speedMbps: Number(s.toFixed(2)),
|
|
9
9
|
speedKBps: Number(n.toFixed(2)),
|
|
10
10
|
downloadTime: Number(e.toFixed(2)),
|
|
11
11
|
transferSize: t.transferSize
|
|
@@ -14,17 +14,17 @@ function f(t) {
|
|
|
14
14
|
function p() {
|
|
15
15
|
return performance.getEntriesByType("resource").filter(
|
|
16
16
|
(e) => e instanceof PerformanceResourceTiming && e.transferSize > 0
|
|
17
|
-
).map(
|
|
17
|
+
).map(l).filter((e) => e !== null);
|
|
18
18
|
}
|
|
19
|
-
function
|
|
19
|
+
function h(t) {
|
|
20
20
|
performance.getEntriesByName(t).forEach(() => {
|
|
21
21
|
performance.clearResourceTimings();
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
-
function
|
|
24
|
+
function m(t, e = { fast: 10, medium: 2 }) {
|
|
25
25
|
return t >= e.fast ? "fast" : t >= e.medium ? "medium" : t > 0 ? "slow" : "unknown";
|
|
26
26
|
}
|
|
27
|
-
class
|
|
27
|
+
class T {
|
|
28
28
|
options;
|
|
29
29
|
observer = null;
|
|
30
30
|
constructor(e = {}) {
|
|
@@ -33,7 +33,8 @@ class b {
|
|
|
33
33
|
internetUrl: e.internetUrl || "",
|
|
34
34
|
timeout: e.timeout || 1e4,
|
|
35
35
|
autoDetect: e.autoDetect ?? !0,
|
|
36
|
-
thresholds: e.thresholds || { fast: 10, medium: 2 }
|
|
36
|
+
thresholds: e.thresholds || { fast: 10, medium: 2 },
|
|
37
|
+
resourceType: e.resourceType || "image"
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
@@ -57,57 +58,74 @@ class b {
|
|
|
57
58
|
/**
|
|
58
59
|
* 测试单个URL
|
|
59
60
|
*/
|
|
60
|
-
testSingleUrl(e,
|
|
61
|
-
return new Promise((n,
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
for (const
|
|
66
|
-
if (
|
|
67
|
-
const i =
|
|
61
|
+
testSingleUrl(e, s) {
|
|
62
|
+
return new Promise((n, o) => {
|
|
63
|
+
const r = `${e}?t=${Date.now()}`;
|
|
64
|
+
h(r);
|
|
65
|
+
const c = new PerformanceObserver((d) => {
|
|
66
|
+
for (const u of d.getEntries())
|
|
67
|
+
if (u.entryType === "resource" && u.name.includes(e)) {
|
|
68
|
+
const i = l(u);
|
|
68
69
|
if (i) {
|
|
69
|
-
const
|
|
70
|
+
const f = {
|
|
70
71
|
speedMbps: i.speedMbps,
|
|
71
72
|
speedKBps: i.speedKBps,
|
|
72
|
-
networkType:
|
|
73
|
+
networkType: m(
|
|
73
74
|
i.speedMbps,
|
|
74
75
|
this.options.thresholds
|
|
75
76
|
),
|
|
76
|
-
isIntranet:
|
|
77
|
+
isIntranet: s,
|
|
77
78
|
duration: i.downloadTime,
|
|
78
79
|
transferSize: i.transferSize,
|
|
79
80
|
resourceUrl: e
|
|
80
81
|
};
|
|
81
|
-
|
|
82
|
+
c.disconnect(), n(f);
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
85
|
});
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
86
|
+
c.observe({ entryTypes: ["resource"] });
|
|
87
|
+
const a = setTimeout(() => {
|
|
88
|
+
c.disconnect(), o(new Error(`测速超时: ${e}`));
|
|
88
89
|
}, this.options.timeout);
|
|
89
|
-
fetch(o,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
90
|
+
this.options.resourceType === "fetch" ? this.loadWithFetch(r, a, c, o) : this.loadWithImage(r, a, c, o);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 使用 Image 对象加载资源(默认方式,不受跨域限制)
|
|
95
|
+
*/
|
|
96
|
+
loadWithImage(e, s, n, o) {
|
|
97
|
+
const r = new Image();
|
|
98
|
+
r.onload = () => {
|
|
99
|
+
clearTimeout(s);
|
|
100
|
+
}, r.onerror = () => {
|
|
101
|
+
clearTimeout(s), n.disconnect(), o(new Error(`资源加载失败: ${e}`));
|
|
102
|
+
}, r.src = e;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 使用 fetch API 加载资源(需要 CORS 支持)
|
|
106
|
+
*/
|
|
107
|
+
loadWithFetch(e, s, n, o) {
|
|
108
|
+
fetch(e, {
|
|
109
|
+
method: "GET",
|
|
110
|
+
cache: "no-store"
|
|
111
|
+
// 禁用缓存
|
|
112
|
+
}).then((r) => {
|
|
113
|
+
if (!r.ok)
|
|
114
|
+
throw new Error(`HTTP error! status: ${r.status}`);
|
|
115
|
+
return r.blob();
|
|
116
|
+
}).then(() => {
|
|
117
|
+
clearTimeout(s);
|
|
118
|
+
}).catch((r) => {
|
|
119
|
+
clearTimeout(s), n.disconnect(), o(new Error(`资源加载失败: ${r.message}`));
|
|
102
120
|
});
|
|
103
121
|
}
|
|
104
122
|
/**
|
|
105
123
|
* 监听特定资源的性能数据
|
|
106
124
|
*/
|
|
107
|
-
observeResource(e,
|
|
108
|
-
const n = new PerformanceObserver((
|
|
109
|
-
for (const
|
|
110
|
-
|
|
125
|
+
observeResource(e, s) {
|
|
126
|
+
const n = new PerformanceObserver((o) => {
|
|
127
|
+
for (const r of o.getEntries())
|
|
128
|
+
r.entryType === "resource" && r.name.includes(e) && s(r);
|
|
111
129
|
});
|
|
112
130
|
return n.observe({ entryTypes: ["resource"] }), () => n.disconnect();
|
|
113
131
|
}
|
|
@@ -124,10 +142,10 @@ class b {
|
|
|
124
142
|
this.observer && (this.observer.disconnect(), this.observer = null);
|
|
125
143
|
}
|
|
126
144
|
}
|
|
127
|
-
class
|
|
145
|
+
class y {
|
|
128
146
|
tester;
|
|
129
147
|
constructor(e = {}) {
|
|
130
|
-
this.tester = new
|
|
148
|
+
this.tester = new T(e);
|
|
131
149
|
}
|
|
132
150
|
/**
|
|
133
151
|
* 执行网速测试
|
|
@@ -144,8 +162,8 @@ class S {
|
|
|
144
162
|
/**
|
|
145
163
|
* 监听特定资源的性能数据
|
|
146
164
|
*/
|
|
147
|
-
observeResource(e,
|
|
148
|
-
return this.tester.observeResource(e,
|
|
165
|
+
observeResource(e, s) {
|
|
166
|
+
return this.tester.observeResource(e, s);
|
|
149
167
|
}
|
|
150
168
|
/**
|
|
151
169
|
* 更新配置
|
|
@@ -160,13 +178,13 @@ class S {
|
|
|
160
178
|
this.tester.destroy();
|
|
161
179
|
}
|
|
162
180
|
}
|
|
163
|
-
function
|
|
164
|
-
return new
|
|
181
|
+
function b(t) {
|
|
182
|
+
return new y(t);
|
|
165
183
|
}
|
|
166
184
|
export {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
185
|
+
y as NetworkSpeedSDK,
|
|
186
|
+
l as calcSpeedByResource,
|
|
187
|
+
b as createNetworkSpeedSDK,
|
|
188
|
+
m as evaluateNetworkType,
|
|
171
189
|
p as getAllResourcesSpeeds
|
|
172
190
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(n,c){typeof exports=="object"&&typeof module<"u"?c(exports):typeof define=="function"&&define.amd?define(["exports"],c):(n=typeof globalThis<"u"?globalThis:n||self,c(n.NetworkSpeedJS={}))})(this,(function(n){"use strict";function c(t){const e=t.responseEnd-t.responseStart;if(e<=0||t.transferSize===0)return null;const s=t.transferSize*8/e/1e3,o=t.transferSize/e;return{name:t.name,speedMbps:Number(s.toFixed(2)),speedKBps:Number(o.toFixed(2)),downloadTime:Number(e.toFixed(2)),transferSize:t.transferSize}}function d(){return performance.getEntriesByType("resource").filter(e=>e instanceof PerformanceResourceTiming&&e.transferSize>0).map(c).filter(e=>e!==null)}function m(t){performance.getEntriesByName(t).forEach(()=>{performance.clearResourceTimings()})}function f(t,e={fast:10,medium:2}){return t>=e.fast?"fast":t>=e.medium?"medium":t>0?"slow":"unknown"}class S{options;observer=null;constructor(e={}){this.options={intranetUrl:e.intranetUrl||"",internetUrl:e.internetUrl||"",timeout:e.timeout||1e4,autoDetect:e.autoDetect??!0,thresholds:e.thresholds||{fast:10,medium:2},resourceType:e.resourceType||"image"}}async test(){return this.options.autoDetect?this.testWithAutoDetect():this.testSingleUrl(this.options.internetUrl,!1)}async testWithAutoDetect(){if(this.options.intranetUrl)try{return await this.testSingleUrl(this.options.intranetUrl,!0)}catch{console.log("内网测速失败,切换到外网测速")}return this.testSingleUrl(this.options.internetUrl,!1)}testSingleUrl(e,s){return new Promise((o,i)=>{const r=`${e}?t=${Date.now()}`;m(r);const a=new PerformanceObserver(T=>{for(const l of T.getEntries())if(l.entryType==="resource"&&l.name.includes(e)){const u=c(l);if(u){const w={speedMbps:u.speedMbps,speedKBps:u.speedKBps,networkType:f(u.speedMbps,this.options.thresholds),isIntranet:s,duration:u.downloadTime,transferSize:u.transferSize,resourceUrl:e};a.disconnect(),o(w)}}});a.observe({entryTypes:["resource"]});const h=setTimeout(()=>{a.disconnect(),i(new Error(`测速超时: ${e}`))},this.options.timeout);this.options.resourceType==="fetch"?this.loadWithFetch(r,h,a,i):this.loadWithImage(r,h,a,i)})}loadWithImage(e,s,o,i){const r=new Image;r.onload=()=>{clearTimeout(s)},r.onerror=()=>{clearTimeout(s),o.disconnect(),i(new Error(`资源加载失败: ${e}`))},r.src=e}loadWithFetch(e,s,o,i){fetch(e,{method:"GET",cache:"no-store"}).then(r=>{if(!r.ok)throw new Error(`HTTP error! status: ${r.status}`);return r.blob()}).then(()=>{clearTimeout(s)}).catch(r=>{clearTimeout(s),o.disconnect(),i(new Error(`资源加载失败: ${r.message}`))})}observeResource(e,s){const o=new PerformanceObserver(i=>{for(const r of i.getEntries())r.entryType==="resource"&&r.name.includes(e)&&s(r)});return o.observe({entryTypes:["resource"]}),()=>o.disconnect()}updateOptions(e){this.options={...this.options,...e}}destroy(){this.observer&&(this.observer.disconnect(),this.observer=null)}}class p{tester;constructor(e={}){this.tester=new S(e)}async test(){return this.tester.test()}getAllResourcesSpeeds(){return d()}observeResource(e,s){return this.tester.observeResource(e,s)}updateOptions(e){this.tester.updateOptions(e)}destroy(){this.tester.destroy()}}function y(t){return new p(t)}n.NetworkSpeedSDK=p,n.calcSpeedByResource=c,n.createNetworkSpeedSDK=y,n.evaluateNetworkType=f,n.getAllResourcesSpeeds=d,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "network-speed-js",
|
|
3
3
|
"private": false,
|
|
4
4
|
"description": "A framework-agnostic network speed testing SDK based on Performance API with intranet/internet auto-detection support",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.3",
|
|
6
6
|
"author": "Sunny-117",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"keywords": [
|