network-speed-js 1.0.4 → 1.0.5

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 CHANGED
@@ -53,11 +53,31 @@ npm install network-speed-js
53
53
 
54
54
  ### 原生 JavaScript / TypeScript
55
55
 
56
+ **方式一:使用图片资源测速(推荐,默认模式,无需CORS)**
57
+
56
58
  ```typescript
57
59
  import { NetworkSpeedSDK } from 'network-speed-js';
58
60
 
59
61
  const sdk = new NetworkSpeedSDK({
60
- internetUrl: 'https://cdn.example.com/test.bin',
62
+ internetImageUrl: 'https://cdn.example.com/test-image.jpg',
63
+ // 可选:内网图片URL
64
+ intranetImageUrl: 'https://internal-cdn.com/test-image.jpg',
65
+ });
66
+
67
+ const result = await sdk.test();
68
+ console.log(`网速: ${result.speedMbps} Mbps`);
69
+ ```
70
+
71
+ **方式二:使用任意资源测速(需要CORS支持)**
72
+
73
+ ```typescript
74
+ import { NetworkSpeedSDK } from 'network-speed-js';
75
+
76
+ const sdk = new NetworkSpeedSDK({
77
+ internetUrl: 'https://cdn.example.com/test-file.bin',
78
+ useFetch: true, // 启用fetch模式
79
+ // 可选:内网资源URL
80
+ intranetUrl: 'https://internal-cdn.com/test-file.bin',
61
81
  });
62
82
 
63
83
  const result = await sdk.test();
@@ -84,7 +104,7 @@ const result = ref(null);
84
104
  const testSpeed = async () => {
85
105
  loading.value = true;
86
106
  const sdk = new NetworkSpeedSDK({
87
- internetUrl: 'https://cdn.example.com/test.bin',
107
+ internetImageUrl: 'https://cdn.example.com/test-image.jpg',
88
108
  });
89
109
  result.value = await sdk.test();
90
110
  loading.value = false;
@@ -105,7 +125,7 @@ function SpeedTest() {
105
125
  const testSpeed = async () => {
106
126
  setLoading(true);
107
127
  const sdk = new NetworkSpeedSDK({
108
- internetUrl: 'https://cdn.example.com/test.bin',
128
+ internetImageUrl: 'https://cdn.example.com/test-image.jpg',
109
129
  });
110
130
  const data = await sdk.test();
111
131
  setResult(data);
@@ -145,7 +165,7 @@ export class SpeedTestComponent {
145
165
  async testSpeed() {
146
166
  this.loading = true;
147
167
  const sdk = new NetworkSpeedSDK({
148
- internetUrl: 'https://cdn.example.com/test.bin',
168
+ internetImageUrl: 'https://cdn.example.com/test-image.jpg',
149
169
  });
150
170
  this.result = await sdk.test();
151
171
  this.loading = false;
@@ -163,29 +183,63 @@ export class SpeedTestComponent {
163
183
  new NetworkSpeedSDK(options?: SpeedTestOptions)
164
184
  ```
165
185
 
166
- **配置选项:**
186
+ **参数说明:**
187
+ - `options`(可选):配置选项
188
+ - 如果传入配置,可以执行测速
189
+ - 如果不传配置,只能使用工具函数(`getAllResourcesSpeeds`、`observeResource`)
167
190
 
168
- | 参数 | 类型 | 默认值 | 说明 |
169
- |------|------|--------|------|
170
- | `intranetUrl` | `string` | `''` | 内网测速资源URL |
171
- | `internetUrl` | `string` | `''` | 外网测速资源URL(必填) |
172
- | `autoDetect` | `boolean` | `true` | 是否自动检测内外网 |
173
- | `timeout` | `number` | `10000` | 超时时间 (ms) |
174
- | `thresholds` | `object` | `{fast: 10, medium: 2}` | 网速评估阈值 (Mbps) |
175
- | `resourceType` | `'image' \| 'fetch'` | `'image'` | 资源类型(见下方说明) |
191
+ **配置选项(两种模式):**
176
192
 
177
- **resourceType 说明:**
193
+ **模式一:图片模式(默认,推荐)**
178
194
 
179
- - `'image'`(默认):使用 Image 对象加载
180
- - 不受跨域限制
181
- -适用于图片资源(.jpg、.png、.webp 等)
182
- - 无需服务器配置 CORS
183
- - ⚠️ 仅支持图片格式
195
+ ```typescript
196
+ interface ImageSpeedTestOptions {
197
+ internetImageUrl: string; // 必填:外网图片URL
198
+ intranetImageUrl?: string; // 可选:内网图片URL
199
+ timeout?: number; // 可选:超时时间 (ms),默认 10000
200
+ autoDetect?: boolean; // 可选:是否自动检测内外网,默认 true
201
+ thresholds?: { // 可选:网速评估阈值 (Mbps)
202
+ fast: number; // 默认 10
203
+ medium: number; // 默认 2
204
+ };
205
+ }
206
+ ```
207
+
208
+ **模式二:Fetch模式(支持任意资源,需要CORS)**
209
+
210
+ ```typescript
211
+ interface FetchSpeedTestOptions {
212
+ internetUrl: string; // ✅ 必填:外网资源URL
213
+ useFetch: true; // ✅ 必填:启用fetch模式
214
+ intranetUrl?: string; // 可选:内网资源URL
215
+ timeout?: number; // 可选:超时时间 (ms),默认 10000
216
+ autoDetect?: boolean; // 可选:是否自动检测内外网,默认 true
217
+ thresholds?: { // 可选:网速评估阈值 (Mbps)
218
+ fast: number; // 默认 10
219
+ medium: number; // 默认 2
220
+ };
221
+ }
222
+ ```
223
+
224
+ **使用示例:**
184
225
 
185
- - `'fetch'`:使用 fetch API 加载
186
- -支持任意类型资源(.bin、.json、.txt 等)
187
- - ⚠️ 需要服务器配置 CORS
188
- - ⚠️ 受跨域限制
226
+ ```typescript
227
+ //图片模式(只需要图片URL)
228
+ const sdk1 = new NetworkSpeedSDK({
229
+ internetImageUrl: 'https://cdn.example.com/test.jpg',
230
+ });
231
+
232
+ // ✅ Fetch模式(需要URL + useFetch: true)
233
+ const sdk2 = new NetworkSpeedSDK({
234
+ internetUrl: 'https://cdn.example.com/test.bin',
235
+ useFetch: true,
236
+ });
237
+
238
+ // ✅ 无参数实例化(仅用于工具函数)
239
+ const sdk3 = new NetworkSpeedSDK();
240
+ const speeds = sdk3.getAllResourcesSpeeds(); // ✅ 可以使用
241
+ await sdk3.test(); // ❌ 会抛出错误:SDK未配置
242
+ ```
189
243
 
190
244
  #### 方法
191
245
 
@@ -283,8 +337,7 @@ interface ResourceSpeedInfo {
283
337
 
284
338
  ```typescript
285
339
  const sdk = new NetworkSpeedSDK({
286
- internetUrl: 'https://cdn.example.com/test-image.jpg',
287
- // resourceType: 'image', // 默认值,可省略
340
+ internetImageUrl: 'https://cdn.example.com/test-image.jpg',
288
341
  });
289
342
 
290
343
  const result = await sdk.test();
@@ -295,7 +348,7 @@ const result = await sdk.test();
295
348
  ```typescript
296
349
  const sdk = new NetworkSpeedSDK({
297
350
  internetUrl: 'https://cdn.example.com/test-file.bin',
298
- resourceType: 'fetch', // 使用 fetch API
351
+ useFetch: true, // 必须启用fetch模式
299
352
  });
300
353
 
301
354
  const result = await sdk.test();
@@ -304,9 +357,18 @@ const result = await sdk.test();
304
357
  ### 3. 内外网自动检测
305
358
 
306
359
  ```typescript
360
+ // 图片模式
361
+ const sdk = new NetworkSpeedSDK({
362
+ intranetImageUrl: 'https://internal-cdn.company.com/test.jpg',
363
+ internetImageUrl: 'https://public-cdn.example.com/test.jpg',
364
+ autoDetect: true,
365
+ });
366
+
367
+ // 或 Fetch模式
307
368
  const sdk = new NetworkSpeedSDK({
308
- intranetUrl: 'https://internal-cdn.company.com/test.jpg',
309
- internetUrl: 'https://public-cdn.example.com/test.jpg',
369
+ intranetUrl: 'https://internal-cdn.company.com/test.bin',
370
+ internetUrl: 'https://public-cdn.example.com/test.bin',
371
+ useFetch: true,
310
372
  autoDetect: true,
311
373
  });
312
374
 
@@ -4,23 +4,51 @@ import type { SpeedTestOptions, SpeedTestResult, ResourceSpeedInfo } from './typ
4
4
  */
5
5
  export declare class NetworkSpeedSDK {
6
6
  private tester;
7
+ /**
8
+ * 创建SDK实例
9
+ * @param options 配置选项(可选,如果不传则只能使用工具函数,不能执行测速)
10
+ *
11
+ * @example
12
+ * // 图片模式(默认,推荐)
13
+ * const sdk = new NetworkSpeedSDK({
14
+ * internetImageUrl: 'https://cdn.example.com/test.jpg',
15
+ * });
16
+ *
17
+ * @example
18
+ * // Fetch模式(需要CORS)
19
+ * const sdk = new NetworkSpeedSDK({
20
+ * internetUrl: 'https://cdn.example.com/test.bin',
21
+ * useFetch: true,
22
+ * });
23
+ *
24
+ * @example
25
+ * // 仅使用工具函数
26
+ * const sdk = new NetworkSpeedSDK();
27
+ * const speeds = sdk.getAllResourcesSpeeds();
28
+ */
7
29
  constructor(options?: SpeedTestOptions);
8
30
  /**
9
31
  * 执行网速测试
32
+ * @throws {Error} 如果SDK未配置
10
33
  */
11
34
  test(): Promise<SpeedTestResult>;
12
35
  /**
13
36
  * 获取所有已加载资源的速度信息
37
+ * @returns 资源速度信息数组
14
38
  */
15
39
  getAllResourcesSpeeds(): ResourceSpeedInfo[];
16
40
  /**
17
41
  * 监听特定资源的性能数据
42
+ * @param urlPattern URL匹配模式
43
+ * @param callback 回调函数
44
+ * @returns 停止监听的函数
18
45
  */
19
46
  observeResource(urlPattern: string, callback: (entry: PerformanceResourceTiming) => void): () => void;
20
47
  /**
21
48
  * 更新配置
49
+ * @param options 新的配置选项
22
50
  */
23
- updateOptions(options: Partial<SpeedTestOptions>): void;
51
+ updateOptions(options: SpeedTestOptions): void;
24
52
  /**
25
53
  * 销毁SDK实例
26
54
  */
@@ -28,6 +56,13 @@ export declare class NetworkSpeedSDK {
28
56
  }
29
57
  /**
30
58
  * 创建SDK实例的工厂函数
59
+ * @param options 配置选项
60
+ * @returns SDK实例
61
+ *
62
+ * @example
63
+ * const sdk = createNetworkSpeedSDK({
64
+ * internetImageUrl: 'https://cdn.example.com/test.jpg',
65
+ * });
31
66
  */
32
67
  export declare function createNetworkSpeedSDK(options?: SpeedTestOptions): NetworkSpeedSDK;
33
68
  export default NetworkSpeedSDK;
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEpF;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAc;gBAEhB,OAAO,GAAE,gBAAqB;IAI1C;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC;IAItC;;OAEG;IACH,qBAAqB,IAAI,iBAAiB,EAAE;IAI5C;;OAEG;IACH,eAAe,CACb,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,IAAI,GACnD,MAAM,IAAI;IAIb;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI;IAIvD;;OAEG;IACH,OAAO,IAAI,IAAI;CAGhB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,eAAe,CAEjF;AAGD,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEpF;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAA4B;IAE1C;;;;;;;;;;;;;;;;;;;;;OAqBG;gBACS,OAAO,CAAC,EAAE,gBAAgB;IAMtC;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC;IAatC;;;OAGG;IACH,qBAAqB,IAAI,iBAAiB,EAAE;IAI5C;;;;;OAKG;IACH,eAAe,CACb,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,IAAI,GACnD,MAAM,IAAI;IAUb;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAK9C;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,eAAe,CAEjF;AAGD,eAAe,eAAe,CAAC"}
@@ -1,11 +1,25 @@
1
1
  import type { SpeedTestResult, SpeedTestOptions, PerformanceEntryCallback } from './types';
2
+ /**
3
+ * 内部标准化配置
4
+ */
5
+ interface NormalizedOptions {
6
+ intranetUrl: string;
7
+ internetUrl: string;
8
+ timeout: number;
9
+ autoDetect: boolean;
10
+ thresholds: {
11
+ fast: number;
12
+ medium: number;
13
+ };
14
+ useFetch: boolean;
15
+ }
2
16
  /**
3
17
  * 网速测试核心类
4
18
  */
5
19
  export declare class SpeedTester {
6
20
  private options;
7
21
  private observer;
8
- constructor(options?: SpeedTestOptions);
22
+ constructor(options: SpeedTestOptions);
9
23
  /**
10
24
  * 执行测速
11
25
  */
@@ -33,10 +47,11 @@ export declare class SpeedTester {
33
47
  /**
34
48
  * 更新配置
35
49
  */
36
- updateOptions(options: Partial<SpeedTestOptions>): void;
50
+ updateOptions(options: Partial<NormalizedOptions>): void;
37
51
  /**
38
52
  * 销毁实例
39
53
  */
40
54
  destroy(): void;
41
55
  }
56
+ export {};
42
57
  //# sourceMappingURL=speed-tester.d.ts.map
@@ -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;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"}
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,UAAU,iBAAiB;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,QAAQ,CAAoC;gBAExC,OAAO,EAAE,gBAAgB;IAyBrC;;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,iBAAiB,CAAC,GAAG,IAAI;IAIxD;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB"}
@@ -33,17 +33,9 @@ export interface ResourceSpeedInfo {
33
33
  transferSize: number;
34
34
  }
35
35
  /**
36
- * 资源类型
36
+ * 基础配置选项
37
37
  */
38
- export type ResourceType = 'image' | 'fetch';
39
- /**
40
- * SDK配置选项
41
- */
42
- export interface SpeedTestOptions {
43
- /** 内网测速资源URL */
44
- intranetUrl?: string;
45
- /** 外网测速资源URL */
46
- internetUrl?: string;
38
+ interface BaseSpeedTestOptions {
47
39
  /** 超时时间 (ms) */
48
40
  timeout?: number;
49
41
  /** 是否自动检测内外网 */
@@ -53,17 +45,36 @@ export interface SpeedTestOptions {
53
45
  fast: number;
54
46
  medium: number;
55
47
  };
56
- /**
57
- * 资源类型
58
- * - 'image': 使用 Image 对象加载(默认,不受跨域限制,适用于图片资源)
59
- * - 'fetch': 使用 fetch API 加载(需要服务器支持 CORS,适用于任意资源)
60
- */
61
- resourceType?: ResourceType;
62
48
  }
49
+ /**
50
+ * 图片模式配置(默认,不受跨域限制)
51
+ */
52
+ export interface ImageSpeedTestOptions extends BaseSpeedTestOptions {
53
+ /** 内网测速图片URL */
54
+ intranetImageUrl?: string;
55
+ /** 外网测速图片URL(必填) */
56
+ internetImageUrl: string;
57
+ }
58
+ /**
59
+ * Fetch模式配置(支持任意资源,需要CORS)
60
+ */
61
+ export interface FetchSpeedTestOptions extends BaseSpeedTestOptions {
62
+ /** 内网测速资源URL */
63
+ intranetUrl?: string;
64
+ /** 外网测速资源URL(必填) */
65
+ internetUrl: string;
66
+ /** 使用fetch模式 */
67
+ useFetch: true;
68
+ }
69
+ /**
70
+ * SDK配置选项(联合类型)
71
+ */
72
+ export type SpeedTestOptions = ImageSpeedTestOptions | FetchSpeedTestOptions;
63
73
  /**
64
74
  * Performance Observer 回调参数
65
75
  */
66
76
  export interface PerformanceEntryCallback {
67
77
  (entry: PerformanceResourceTiming): void;
68
78
  }
79
+ export {};
69
80
  //# sourceMappingURL=types.d.ts.map
@@ -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,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"}
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,UAAU,oBAAoB;IAC5B,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;CACH;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,gBAAgB;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB;IACpB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,gBAAgB;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB;IAChB,QAAQ,EAAE,IAAI,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAAG,qBAAqB,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,CAAC,KAAK,EAAE,yBAAyB,GAAG,IAAI,CAAC;CAC1C"}
@@ -1,4 +1,4 @@
1
- function l(t) {
1
+ function h(t) {
2
2
  const e = t.responseEnd - t.responseStart;
3
3
  if (e <= 0 || t.transferSize === 0)
4
4
  return null;
@@ -11,30 +11,37 @@ function l(t) {
11
11
  transferSize: t.transferSize
12
12
  };
13
13
  }
14
- function p() {
14
+ function f() {
15
15
  return performance.getEntriesByType("resource").filter(
16
16
  (e) => e instanceof PerformanceResourceTiming && e.transferSize > 0
17
- ).map(l).filter((e) => e !== null);
17
+ ).map(h).filter((e) => e !== null);
18
18
  }
19
- function h(t) {
19
+ function p(t) {
20
20
  performance.getEntriesByName(t).forEach(() => {
21
21
  performance.clearResourceTimings();
22
22
  });
23
23
  }
24
- function m(t, e = { fast: 10, medium: 2 }) {
24
+ function w(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 T {
27
+ class a {
28
28
  options;
29
29
  observer = null;
30
- constructor(e = {}) {
31
- this.options = {
30
+ constructor(e) {
31
+ "useFetch" in e && e.useFetch ? this.options = {
32
32
  intranetUrl: e.intranetUrl || "",
33
- internetUrl: e.internetUrl || "",
33
+ internetUrl: e.internetUrl,
34
34
  timeout: e.timeout || 1e4,
35
35
  autoDetect: e.autoDetect ?? !0,
36
36
  thresholds: e.thresholds || { fast: 10, medium: 2 },
37
- resourceType: e.resourceType || "image"
37
+ useFetch: !0
38
+ } : this.options = {
39
+ intranetUrl: "intranetImageUrl" in e && e.intranetImageUrl || "",
40
+ internetUrl: "internetImageUrl" in e ? e.internetImageUrl : "",
41
+ timeout: e.timeout || 1e4,
42
+ autoDetect: e.autoDetect ?? !0,
43
+ thresholds: e.thresholds || { fast: 10, medium: 2 },
44
+ useFetch: !1
38
45
  };
39
46
  }
40
47
  /**
@@ -61,16 +68,16 @@ class T {
61
68
  testSingleUrl(e, s) {
62
69
  return new Promise((n, o) => {
63
70
  const r = `${e}?t=${Date.now()}`;
64
- h(r);
65
- const c = new PerformanceObserver((d) => {
66
- for (const u of d.getEntries())
71
+ p(r);
72
+ const c = new PerformanceObserver((m) => {
73
+ for (const u of m.getEntries())
67
74
  if (u.entryType === "resource" && u.name.includes(e)) {
68
- const i = l(u);
75
+ const i = h(u);
69
76
  if (i) {
70
- const f = {
77
+ const d = {
71
78
  speedMbps: i.speedMbps,
72
79
  speedKBps: i.speedKBps,
73
- networkType: m(
80
+ networkType: w(
74
81
  i.speedMbps,
75
82
  this.options.thresholds
76
83
  ),
@@ -79,15 +86,15 @@ class T {
79
86
  transferSize: i.transferSize,
80
87
  resourceUrl: e
81
88
  };
82
- c.disconnect(), n(f);
89
+ c.disconnect(), n(d);
83
90
  }
84
91
  }
85
92
  });
86
93
  c.observe({ entryTypes: ["resource"] });
87
- const a = setTimeout(() => {
94
+ const l = setTimeout(() => {
88
95
  c.disconnect(), o(new Error(`测速超时: ${e}`));
89
96
  }, this.options.timeout);
90
- this.options.resourceType === "fetch" ? this.loadWithFetch(r, a, c, o) : this.loadWithImage(r, a, c, o);
97
+ this.options.useFetch ? this.loadWithFetch(r, l, c, o) : this.loadWithImage(r, l, c, o);
91
98
  });
92
99
  }
93
100
  /**
@@ -98,7 +105,7 @@ class T {
98
105
  r.onload = () => {
99
106
  clearTimeout(s);
100
107
  }, r.onerror = () => {
101
- clearTimeout(s), n.disconnect(), o(new Error(`资源加载失败: ${e}`));
108
+ clearTimeout(s), n.disconnect(), o(new Error(`图片加载失败: ${e}`));
102
109
  }, r.src = e;
103
110
  }
104
111
  /**
@@ -142,49 +149,87 @@ class T {
142
149
  this.observer && (this.observer.disconnect(), this.observer = null);
143
150
  }
144
151
  }
145
- class y {
146
- tester;
147
- constructor(e = {}) {
148
- this.tester = new T(e);
152
+ class S {
153
+ tester = null;
154
+ /**
155
+ * 创建SDK实例
156
+ * @param options 配置选项(可选,如果不传则只能使用工具函数,不能执行测速)
157
+ *
158
+ * @example
159
+ * // 图片模式(默认,推荐)
160
+ * const sdk = new NetworkSpeedSDK({
161
+ * internetImageUrl: 'https://cdn.example.com/test.jpg',
162
+ * });
163
+ *
164
+ * @example
165
+ * // Fetch模式(需要CORS)
166
+ * const sdk = new NetworkSpeedSDK({
167
+ * internetUrl: 'https://cdn.example.com/test.bin',
168
+ * useFetch: true,
169
+ * });
170
+ *
171
+ * @example
172
+ * // 仅使用工具函数
173
+ * const sdk = new NetworkSpeedSDK();
174
+ * const speeds = sdk.getAllResourcesSpeeds();
175
+ */
176
+ constructor(e) {
177
+ e && (this.tester = new a(e));
149
178
  }
150
179
  /**
151
180
  * 执行网速测试
181
+ * @throws {Error} 如果SDK未配置
152
182
  */
153
183
  async test() {
184
+ if (!this.tester)
185
+ throw new Error(
186
+ `SDK未配置,请在构造函数中传入配置选项。
187
+ 示例:
188
+ new NetworkSpeedSDK({ internetImageUrl: "https://cdn.example.com/test.jpg" })
189
+ 或:
190
+ new NetworkSpeedSDK({ internetUrl: "https://cdn.example.com/test.bin", useFetch: true })`
191
+ );
154
192
  return this.tester.test();
155
193
  }
156
194
  /**
157
195
  * 获取所有已加载资源的速度信息
196
+ * @returns 资源速度信息数组
158
197
  */
159
198
  getAllResourcesSpeeds() {
160
- return p();
199
+ return f();
161
200
  }
162
201
  /**
163
202
  * 监听特定资源的性能数据
203
+ * @param urlPattern URL匹配模式
204
+ * @param callback 回调函数
205
+ * @returns 停止监听的函数
164
206
  */
165
207
  observeResource(e, s) {
166
- return this.tester.observeResource(e, s);
208
+ return this.tester || (this.tester = new a({
209
+ internetImageUrl: ""
210
+ })), this.tester.observeResource(e, s);
167
211
  }
168
212
  /**
169
213
  * 更新配置
214
+ * @param options 新的配置选项
170
215
  */
171
216
  updateOptions(e) {
172
- this.tester.updateOptions(e);
217
+ this.tester = new a(e);
173
218
  }
174
219
  /**
175
220
  * 销毁SDK实例
176
221
  */
177
222
  destroy() {
178
- this.tester.destroy();
223
+ this.tester && (this.tester.destroy(), this.tester = null);
179
224
  }
180
225
  }
181
- function b(t) {
182
- return new y(t);
226
+ function U(t) {
227
+ return new S(t);
183
228
  }
184
229
  export {
185
- y as NetworkSpeedSDK,
186
- l as calcSpeedByResource,
187
- b as createNetworkSpeedSDK,
188
- m as evaluateNetworkType,
189
- p as getAllResourcesSpeeds
230
+ S as NetworkSpeedSDK,
231
+ h as calcSpeedByResource,
232
+ U as createNetworkSpeedSDK,
233
+ w as evaluateNetworkType,
234
+ f as getAllResourcesSpeeds
190
235
  };
@@ -1 +1,5 @@
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"})}));
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 h(){return performance.getEntriesByType("resource").filter(e=>e instanceof PerformanceResourceTiming&&e.transferSize>0).map(c).filter(e=>e!==null)}function S(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 l{options;observer=null;constructor(e){"useFetch"in e&&e.useFetch?this.options={intranetUrl:e.intranetUrl||"",internetUrl:e.internetUrl,timeout:e.timeout||1e4,autoDetect:e.autoDetect??!0,thresholds:e.thresholds||{fast:10,medium:2},useFetch:!0}:this.options={intranetUrl:"intranetImageUrl"in e&&e.intranetImageUrl||"",internetUrl:"internetImageUrl"in e?e.internetImageUrl:"",timeout:e.timeout||1e4,autoDetect:e.autoDetect??!0,thresholds:e.thresholds||{fast:10,medium:2},useFetch:!1}}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()}`;S(r);const a=new PerformanceObserver(g=>{for(const d of g.getEntries())if(d.entryType==="resource"&&d.name.includes(e)){const u=c(d);if(u){const y={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(y)}}});a.observe({entryTypes:["resource"]});const p=setTimeout(()=>{a.disconnect(),i(new Error(`测速超时: ${e}`))},this.options.timeout);this.options.useFetch?this.loadWithFetch(r,p,a,i):this.loadWithImage(r,p,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 m{tester=null;constructor(e){e&&(this.tester=new l(e))}async test(){if(!this.tester)throw new Error(`SDK未配置,请在构造函数中传入配置选项。
2
+ 示例:
3
+ new NetworkSpeedSDK({ internetImageUrl: "https://cdn.example.com/test.jpg" })
4
+ 或:
5
+ new NetworkSpeedSDK({ internetUrl: "https://cdn.example.com/test.bin", useFetch: true })`);return this.tester.test()}getAllResourcesSpeeds(){return h()}observeResource(e,s){return this.tester||(this.tester=new l({internetImageUrl:""})),this.tester.observeResource(e,s)}updateOptions(e){this.tester=new l(e)}destroy(){this.tester&&(this.tester.destroy(),this.tester=null)}}function w(t){return new m(t)}n.NetworkSpeedSDK=m,n.calcSpeedByResource=c,n.createNetworkSpeedSDK=w,n.evaluateNetworkType=f,n.getAllResourcesSpeeds=h,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.4",
5
+ "version": "1.0.5",
6
6
  "author": "Sunny-117",
7
7
  "license": "MIT",
8
8
  "keywords": [