@net-vert/core 0.0.9 → 0.1.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 +253 -26
- package/dist/index.d.ts +17 -13
- package/dist/index.js +80 -68
- package/dist/index.umd.cjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,58 +104,112 @@ retryApi.get('/unstable-api');
|
|
|
104
104
|
|
|
105
105
|
## 🗂 缓存扩展 `requestExtender.cacheRequestor(options)`
|
|
106
106
|
|
|
107
|
-
`cacheRequestor` 是 `@net-vert/core`
|
|
107
|
+
`cacheRequestor` 是 `@net-vert/core` 内置的智能缓存增强器,提供多维度缓存控制能力,支持同步/异步校验策略,所有cacheRequestor共享一个存储空间。
|
|
108
108
|
|
|
109
109
|
### ✅ 核心特性
|
|
110
110
|
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
|
|
114
|
-
-
|
|
115
|
-
|
|
111
|
+
- **🚀 多级缓存策略**
|
|
112
|
+
内存缓存 + 持久化存储(未来由 `@net-vert/cache` 提供)
|
|
113
|
+
|
|
114
|
+
- **🔗 智能并发合并**
|
|
115
|
+
相同请求共享 Promise,避免重复网络消耗
|
|
116
|
+
|
|
117
|
+
- **⏳ 动态缓存控制**
|
|
118
|
+
支持时间/逻辑双重失效校验机制
|
|
119
|
+
|
|
120
|
+
- **🧩 弹性校验策略**
|
|
121
|
+
支持同步/异步缓存有效性检查
|
|
116
122
|
|
|
117
123
|
---
|
|
118
124
|
|
|
119
|
-
### ⚙️
|
|
125
|
+
### ⚙️ 配置参数
|
|
120
126
|
|
|
121
|
-
| 参数 | 类型
|
|
122
|
-
|
|
123
|
-
| `key` | `(config: UnifiedConfig) => string`
|
|
124
|
-
| `persist` | `boolean`
|
|
125
|
-
| `
|
|
127
|
+
| 参数 | 类型 | 说明 | 默认值 |
|
|
128
|
+
|--------------|--------------------------------------------------------------------|-------------------------------------------------------------|----------------|
|
|
129
|
+
| `key` | `(config: UnifiedConfig) => string` | 自定义缓存键生成规则 | `config.url` |
|
|
130
|
+
| `persist` | `boolean` | 启用持久化存储(默认内存存储) | `false` |
|
|
131
|
+
| `duration` | `number` 或 `({ key, config, response }) => number` | 缓存时间(ms)或动态计算函数 | `Infinity` |
|
|
132
|
+
| `isValid` | `({ key, config, cachedData }) => boolean \| Promise<boolean>` | 缓存有效性校验(支持异步校验) | - |
|
|
126
133
|
|
|
127
134
|
---
|
|
128
135
|
|
|
129
|
-
### 📥
|
|
136
|
+
### 📥 基础使用
|
|
130
137
|
|
|
131
138
|
```typescript
|
|
132
139
|
import { requestExtender } from '@net-vert/core';
|
|
133
140
|
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
key:
|
|
141
|
+
const api = requestExtender.cacheRequestor({
|
|
142
|
+
duration: 3000, // 缓存3秒
|
|
143
|
+
key: config => `${config.method}:${config.url}` // 复合键
|
|
137
144
|
});
|
|
138
145
|
|
|
139
|
-
//
|
|
140
|
-
|
|
146
|
+
// 首次请求将缓存
|
|
147
|
+
api.get('/user').then(console.log);
|
|
141
148
|
|
|
142
|
-
//
|
|
143
|
-
|
|
149
|
+
// 3秒内相同请求直接返回缓存
|
|
150
|
+
api.get('/user').then(console.log);
|
|
144
151
|
```
|
|
145
152
|
|
|
146
|
-
|
|
153
|
+
### 🎯 动态缓存示例
|
|
147
154
|
|
|
148
|
-
|
|
155
|
+
#### 根据响应数据设置缓存时间
|
|
156
|
+
```typescript
|
|
157
|
+
requestExtender.cacheRequestor({
|
|
158
|
+
duration: ({ response }) => response.data.isHot ? 10000 : 3000
|
|
159
|
+
});
|
|
160
|
+
```
|
|
149
161
|
|
|
162
|
+
#### 权限变更时失效缓存
|
|
150
163
|
```typescript
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return response.isHot ? 10000 : 3000;
|
|
164
|
+
requestExtender.cacheRequestor({
|
|
165
|
+
isValid: ({ cachedData }) => {
|
|
166
|
+
return cachedData.value.permission === currentUser.permission
|
|
155
167
|
}
|
|
156
168
|
});
|
|
157
169
|
```
|
|
158
170
|
|
|
171
|
+
#### 异步校验缓存有效性
|
|
172
|
+
```typescript
|
|
173
|
+
requestExtender.cacheRequestor({
|
|
174
|
+
async isValid({ key }) {
|
|
175
|
+
const { valid } = await fetch('/cache/validate', { body: key })
|
|
176
|
+
return valid
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### 🛠 工作机制
|
|
184
|
+
|
|
185
|
+
```mermaid
|
|
186
|
+
graph TB
|
|
187
|
+
A[请求进入] --> B{存在Promise缓存?}
|
|
188
|
+
B -->|是| C[共享请求]
|
|
189
|
+
B -->|否| D{存在物理缓存?}
|
|
190
|
+
D -->|是| E[执行isValid校验]
|
|
191
|
+
E -->|有效| F[返回缓存]
|
|
192
|
+
E -->|无效| G[清理缓存]
|
|
193
|
+
D -->|否| H[发起新请求]
|
|
194
|
+
H --> I[缓存响应数据]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### ⚠️ 注意事项
|
|
200
|
+
|
|
201
|
+
1. **缓存穿透防护**
|
|
202
|
+
当 `isValid` 返回 `false` 时会主动清理缓存,后续请求将触发新请求
|
|
203
|
+
|
|
204
|
+
2. **异步校验建议**
|
|
205
|
+
耗时较长的异步校验建议配合 `duration` 使用,避免校验期间重复请求
|
|
206
|
+
|
|
207
|
+
3. **内存管理**
|
|
208
|
+
高频数据建议启用 `persist` 持久化存储,防止内存溢出
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
|
|
159
213
|
## ♻️ 幂等扩展 `requestExtender.idempotencyRequestor(options)`
|
|
160
214
|
|
|
161
215
|
`idempotencyRequestor` 是基于 `cacheRequestor` 封装的幂等增强器,确保同一参数的请求,在请求未完成前只发送一次,自动合并并发请求,避免重复提交和资源浪费。
|
|
@@ -298,6 +352,179 @@ idempotentApi.post('/user/create', { name: 'Alice' }).then(console.log);
|
|
|
298
352
|
|
|
299
353
|
---
|
|
300
354
|
|
|
355
|
+
```markdown
|
|
356
|
+
# 🚀 并发请求控制器 `createConcurrentPoolRequestor`
|
|
357
|
+
|
|
358
|
+
提供智能并发控制与自动重试能力的请求扩展器,适用于需要精准控制请求并发的场景。
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## 📦 核心模块
|
|
363
|
+
|
|
364
|
+
### 1. 并发池 `ConcurrentPool`
|
|
365
|
+
```typescript
|
|
366
|
+
export class ConcurrentPool {
|
|
367
|
+
parallelCount: number // 最大并行任务数
|
|
368
|
+
tasks: TaskItemList // 待执行任务队列
|
|
369
|
+
runningCount: number // 当前运行中任务数
|
|
370
|
+
|
|
371
|
+
constructor(parallelCount = 4) // 初始化并发池
|
|
372
|
+
|
|
373
|
+
// 添加任务到队列
|
|
374
|
+
add(id: string, task: Task): Promise<any>
|
|
375
|
+
|
|
376
|
+
// 移除指定任务
|
|
377
|
+
remove(id: string): void
|
|
378
|
+
|
|
379
|
+
// 执行单个任务(内部方法)
|
|
380
|
+
private execute(currentTask: TaskItem): void
|
|
381
|
+
|
|
382
|
+
// 启动任务处理(内部调度器)
|
|
383
|
+
private _run(): void
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
### 2. 请求器工厂函数
|
|
390
|
+
```typescript
|
|
391
|
+
createConcurrentPoolRequestor(config): {
|
|
392
|
+
requestor: Requestor, // 增强后的请求器实例
|
|
393
|
+
concurrentPool: ConcurrentPool // 关联的并发池
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## ⚙️ 配置参数
|
|
400
|
+
|
|
401
|
+
| 参数 | 类型 | 说明 | 默认值 |
|
|
402
|
+
|------------------|---------------------------------------|------------------------------|---------------------|
|
|
403
|
+
| `parallelCount` | `number` | 最大并行请求数 | 4 |
|
|
404
|
+
| `createId` | `(config: UnifiedConfig) => string` | 生成唯一任务ID的函数 | 时间戳+随机数 |
|
|
405
|
+
| `retries` | `number` | 失败重试次数 | 0 (不重试) |
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## 🎯 功能特性
|
|
410
|
+
|
|
411
|
+
### 1. 智能并发控制
|
|
412
|
+
```mermaid
|
|
413
|
+
graph TD
|
|
414
|
+
A[新请求到达] --> B{运行中任务 < 最大并发数?}
|
|
415
|
+
B -->|是| C[立即执行]
|
|
416
|
+
B -->|否| D[进入等待队列]
|
|
417
|
+
C --> E[任务完成]
|
|
418
|
+
E --> F{队列有等待任务?}
|
|
419
|
+
F -->|是| G[触发下一个任务]
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### 2. 自动重试机制
|
|
423
|
+
```typescript
|
|
424
|
+
// 集成重试模块的工作流
|
|
425
|
+
sequenceDiagram
|
|
426
|
+
participant P as 并发池
|
|
427
|
+
participant R as 重试模块
|
|
428
|
+
participant S as 服务器
|
|
429
|
+
|
|
430
|
+
P->>R: 执行请求
|
|
431
|
+
R->>S: 尝试请求
|
|
432
|
+
alt 成功
|
|
433
|
+
S-->>R: 返回数据
|
|
434
|
+
R-->>P: 传递结果
|
|
435
|
+
else 失败
|
|
436
|
+
R->>R: 重试逻辑(最多retries次)
|
|
437
|
+
R-->>P: 最终结果/错误
|
|
438
|
+
end
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## 📝 使用示例
|
|
444
|
+
|
|
445
|
+
### 基础使用
|
|
446
|
+
```typescript
|
|
447
|
+
import createConcurrentPoolRequestor from '@/requests/modules/concurrentPoolRequestor'
|
|
448
|
+
|
|
449
|
+
// 创建最大并发数为3的请求器
|
|
450
|
+
const { requestor } = createConcurrentPoolRequestor({
|
|
451
|
+
parallelCount: 3,
|
|
452
|
+
retries: 2, // 失败自动重试2次
|
|
453
|
+
delay: 500 // 重试间隔500ms
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
// 批量发起请求
|
|
457
|
+
const requests = Array(10).fill(0).map(() =>
|
|
458
|
+
requestor.get('/api/data')
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
Promise.all(requests).then(results => {
|
|
462
|
+
console.log('所有请求完成:', results)
|
|
463
|
+
})
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### 高级控制
|
|
467
|
+
```typescript
|
|
468
|
+
// 获取并发池实例进行精细控制
|
|
469
|
+
const { requestor, concurrentPool } = createConcurrentPoolRequestor()
|
|
470
|
+
|
|
471
|
+
// 动态调整并发数
|
|
472
|
+
concurrentPool.parallelCount = 5
|
|
473
|
+
|
|
474
|
+
// 取消特定请求
|
|
475
|
+
const reqId = 'custom-id-123'
|
|
476
|
+
requestor.post('/api/submit', { data }, {
|
|
477
|
+
__id: reqId // 通过配置注入自定义ID
|
|
478
|
+
}).catch(err => {
|
|
479
|
+
if (err.message === 'ABORTED') {
|
|
480
|
+
console.log('请求被主动取消')
|
|
481
|
+
}
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
// 主动取消任务
|
|
485
|
+
concurrentPool.remove(reqId)
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## ⚠️ 注意事项
|
|
491
|
+
|
|
492
|
+
1. **ID生成策略**
|
|
493
|
+
确保`createId`函数生成的ID具有唯一性:
|
|
494
|
+
```typescript
|
|
495
|
+
createId: config => `${config.method}:${config.url}:${hash(config.params)}`
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
2. **资源释放**
|
|
499
|
+
长时间运行的实例需手动释放资源:
|
|
500
|
+
```typescript
|
|
501
|
+
// 清空任务队列
|
|
502
|
+
concurrentPool.tasks.clear()
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## 🛠 设计理念
|
|
508
|
+
|
|
509
|
+
### 1. 队列优先级策略
|
|
510
|
+
```typescript
|
|
511
|
+
// 可扩展为优先级队列
|
|
512
|
+
interface PriorityTaskItem extends TaskItem {
|
|
513
|
+
priority: number
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// 自定义队列实现
|
|
517
|
+
class PriorityQueue implements TaskItemList {
|
|
518
|
+
enqueue(id: string, item: PriorityTaskItem) {
|
|
519
|
+
// 根据优先级插入队列
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
### 1. 队列优先级策略
|
|
523
|
+
```typescript
|
|
524
|
+
一个实例对象控制着单独的并发池
|
|
525
|
+
|
|
526
|
+
```
|
|
527
|
+
|
|
301
528
|
## 📤 开源信息
|
|
302
529
|
|
|
303
530
|
- 仓库地址:[https://github.com/yvygyyth/net-vert](https://github.com/yvygyyth/net-vert)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { TaskQueue } from 'id-queue';
|
|
2
2
|
|
|
3
|
-
declare interface BasicCredentials {
|
|
4
|
-
username: string;
|
|
5
|
-
password: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
3
|
declare class ConcurrentPool {
|
|
9
4
|
parallelCount: number;
|
|
10
5
|
tasks: TaskItemList;
|
|
@@ -26,8 +21,6 @@ declare interface RequestConfig<D = any> {
|
|
|
26
21
|
params?: Record<string, any> | string;
|
|
27
22
|
data?: D;
|
|
28
23
|
timeout?: number;
|
|
29
|
-
auth?: BasicCredentials;
|
|
30
|
-
responseType?: ResponseType;
|
|
31
24
|
onUploadProgress?: <P extends ProgressEvent>(progressEvent: P) => void;
|
|
32
25
|
onDownloadProgress?: <P extends ProgressEvent>(progressEvent: P) => void;
|
|
33
26
|
validateStatus?: ((status: number) => boolean) | null;
|
|
@@ -38,14 +31,23 @@ export declare const requestExtender: {
|
|
|
38
31
|
cacheRequestor: (config?: {
|
|
39
32
|
key?: (config: UnifiedConfig) => string;
|
|
40
33
|
persist?: boolean;
|
|
41
|
-
|
|
34
|
+
duration?: number | (({ key, config, response }: {
|
|
35
|
+
key: string;
|
|
42
36
|
config: UnifiedConfig;
|
|
43
37
|
response: any;
|
|
44
38
|
}) => number);
|
|
39
|
+
isValid?: (params: {
|
|
40
|
+
key: string;
|
|
41
|
+
config: UnifiedConfig;
|
|
42
|
+
cachedData: {
|
|
43
|
+
value: any;
|
|
44
|
+
expiresAt: number;
|
|
45
|
+
};
|
|
46
|
+
}) => boolean | Promise<boolean>;
|
|
45
47
|
}) => Requestor;
|
|
46
48
|
idempotencyRequestor: (genKey?: (config: UnifiedConfig) => string) => Requestor;
|
|
47
49
|
retryRequestor: (config?: RetryOptions) => Requestor;
|
|
48
|
-
concurrentPoolRequestor: (config
|
|
50
|
+
concurrentPoolRequestor: (config?: {
|
|
49
51
|
parallelCount?: number;
|
|
50
52
|
createId?: (config: UnifiedConfig) => string;
|
|
51
53
|
} & RetryOptions) => {
|
|
@@ -55,11 +57,11 @@ export declare const requestExtender: {
|
|
|
55
57
|
};
|
|
56
58
|
|
|
57
59
|
export declare interface Requestor {
|
|
58
|
-
get<R = any, D = any>(url: string, config?: RequestConfig<D
|
|
60
|
+
get<R = any, D = any>(url: string, config?: WithDynamicProps<RequestConfig<D>>): Promise<R>;
|
|
59
61
|
post<R = any, D = any>(url: string, data?: D, config?: RequestConfig<D>): Promise<R>;
|
|
60
|
-
delete<R = any, D = any>(url: string, config?: RequestConfig<D
|
|
61
|
-
put<R = any, D = any>(url: string, data?: D, config?: RequestConfig<D
|
|
62
|
-
request<R = any, D = any>(config: UnifiedConfig<D
|
|
62
|
+
delete<R = any, D = any>(url: string, config?: WithDynamicProps<RequestConfig<D>>): Promise<R>;
|
|
63
|
+
put<R = any, D = any>(url: string, data?: D, config?: WithDynamicProps<RequestConfig<D>>): Promise<R>;
|
|
64
|
+
request<R = any, D = any>(config: WithDynamicProps<UnifiedConfig<D>>): Promise<R>;
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
declare type RetryOptions = {
|
|
@@ -87,4 +89,6 @@ export declare type UnifiedRequestor = <R = any, D = any>(config: UnifiedConfig<
|
|
|
87
89
|
|
|
88
90
|
export declare const useRequestor: (instanceKey?: string) => Requestor;
|
|
89
91
|
|
|
92
|
+
declare type WithDynamicProps<T, V = any> = T & Record<string, V>;
|
|
93
|
+
|
|
90
94
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const f = {
|
|
2
2
|
get: (r, e) => ({
|
|
3
3
|
url: r,
|
|
4
4
|
method: "get",
|
|
@@ -26,12 +26,12 @@ const y = {
|
|
|
26
26
|
}),
|
|
27
27
|
request: (r) => r
|
|
28
28
|
};
|
|
29
|
-
function
|
|
29
|
+
function M(r) {
|
|
30
30
|
const e = {};
|
|
31
|
-
return Object.keys(
|
|
31
|
+
return Object.keys(f).forEach(
|
|
32
32
|
(t) => {
|
|
33
33
|
e[t] = (...s) => {
|
|
34
|
-
const n =
|
|
34
|
+
const n = f[t](...s);
|
|
35
35
|
return r(n);
|
|
36
36
|
};
|
|
37
37
|
}
|
|
@@ -40,14 +40,14 @@ function k(r) {
|
|
|
40
40
|
request: r
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
},
|
|
46
|
-
const e =
|
|
43
|
+
const w = "default", x = /* @__PURE__ */ new Map(), L = (r, e = w) => {
|
|
44
|
+
x.set(e, M(r));
|
|
45
|
+
}, v = (r = w) => {
|
|
46
|
+
const e = x.get(r);
|
|
47
47
|
if (!e) throw new Error(`Requestor实例 ${r} 未注册`);
|
|
48
48
|
return e;
|
|
49
49
|
};
|
|
50
|
-
class
|
|
50
|
+
class j {
|
|
51
51
|
// 是否存在
|
|
52
52
|
has(e) {
|
|
53
53
|
return !!localStorage.getItem(e);
|
|
@@ -82,12 +82,12 @@ class M {
|
|
|
82
82
|
localStorage.clear();
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
const
|
|
85
|
+
const E = new j(), I = /* @__PURE__ */ new Map(), b = (r) => r ? E : I, z = () => {
|
|
86
86
|
const r = /* @__PURE__ */ new Map();
|
|
87
87
|
return {
|
|
88
88
|
getPromise: (o) => r.get(o),
|
|
89
|
-
setPromise: (o,
|
|
90
|
-
r.set(o,
|
|
89
|
+
setPromise: (o, u) => {
|
|
90
|
+
r.set(o, u);
|
|
91
91
|
},
|
|
92
92
|
delPromise: (o) => {
|
|
93
93
|
r.delete(o);
|
|
@@ -96,75 +96,87 @@ const T = new M(), E = /* @__PURE__ */ new Map(), j = (r) => r ? T : E, I = () =
|
|
|
96
96
|
r.clear();
|
|
97
97
|
}
|
|
98
98
|
};
|
|
99
|
-
},
|
|
100
|
-
key: (r) => r.url,
|
|
101
|
-
persist: !1,
|
|
102
|
-
cacheTime: 1 / 0
|
|
103
|
-
}, x = (r, e) => ({
|
|
99
|
+
}, O = (r, e) => ({
|
|
104
100
|
value: r,
|
|
105
101
|
expiresAt: Date.now() + e
|
|
106
|
-
}),
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
102
|
+
}), T = (r) => r.expiresAt > Date.now(), $ = {
|
|
103
|
+
key: (r) => r.url,
|
|
104
|
+
persist: !1,
|
|
105
|
+
duration: 1 / 0
|
|
106
|
+
}, R = (r) => {
|
|
107
|
+
const e = { ...$, ...r }, t = b(e.persist), { getPromise: s, setPromise: n, delPromise: o } = z(), u = {
|
|
108
|
+
get(h, i) {
|
|
109
|
+
return async (...l) => {
|
|
110
|
+
const c = f[i](...l), a = e.key(c), m = s(a);
|
|
111
111
|
if (m)
|
|
112
|
-
return
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return n(a, v), v;
|
|
112
|
+
return m;
|
|
113
|
+
const y = t.get(a);
|
|
114
|
+
let q = !1;
|
|
115
|
+
if (y && T(y)) {
|
|
116
|
+
try {
|
|
117
|
+
q = e.isValid ? await e.isValid({
|
|
118
|
+
key: a,
|
|
119
|
+
config: c,
|
|
120
|
+
cachedData: y
|
|
121
|
+
}) : !0;
|
|
122
|
+
} catch (d) {
|
|
123
|
+
console.error(`校验异常 ${a}`, d);
|
|
124
|
+
}
|
|
125
|
+
q || t.delete(a);
|
|
127
126
|
}
|
|
127
|
+
if (q)
|
|
128
|
+
return y.value;
|
|
129
|
+
const P = Reflect.apply(h[i], h, l).then(async (d) => {
|
|
130
|
+
const S = typeof e.duration == "number" ? e.duration : e.duration({
|
|
131
|
+
key: a,
|
|
132
|
+
config: c,
|
|
133
|
+
response: d
|
|
134
|
+
});
|
|
135
|
+
return t.set(a, O(d, S)), d;
|
|
136
|
+
}).finally(() => {
|
|
137
|
+
o(a);
|
|
138
|
+
});
|
|
139
|
+
return n(a, P), P;
|
|
128
140
|
};
|
|
129
141
|
}
|
|
130
142
|
};
|
|
131
|
-
return new Proxy(
|
|
132
|
-
},
|
|
143
|
+
return new Proxy(v(), u);
|
|
144
|
+
}, D = (r) => {
|
|
133
145
|
const { method: e, url: t, params: s, data: n } = r;
|
|
134
146
|
return [e, t, JSON.stringify(s), JSON.stringify(n)].join("|");
|
|
135
|
-
},
|
|
136
|
-
key: (e) => r ? r(e) :
|
|
147
|
+
}, _ = (r) => R({
|
|
148
|
+
key: (e) => r ? r(e) : D(e),
|
|
137
149
|
persist: !1
|
|
138
|
-
}),
|
|
150
|
+
}), A = {
|
|
139
151
|
retries: 3,
|
|
140
152
|
delay: 0,
|
|
141
153
|
retryCondition: () => !0
|
|
142
|
-
},
|
|
143
|
-
const { retries: e, delay: t, retryCondition: s } = { ...
|
|
144
|
-
get(o,
|
|
145
|
-
return (...
|
|
154
|
+
}, k = (r) => {
|
|
155
|
+
const { retries: e, delay: t, retryCondition: s } = { ...A, ...r }, n = {
|
|
156
|
+
get(o, u) {
|
|
157
|
+
return (...h) => {
|
|
146
158
|
let i = 0;
|
|
147
|
-
const p = () => Reflect.apply(o[
|
|
148
|
-
if (i < e && s(
|
|
159
|
+
const p = () => Reflect.apply(o[u], o, h).catch((l) => {
|
|
160
|
+
if (i < e && s(l)) {
|
|
149
161
|
i++;
|
|
150
|
-
const
|
|
162
|
+
const c = typeof t == "function" ? t(i) : t;
|
|
151
163
|
return new Promise((a) => {
|
|
152
|
-
setTimeout(() => a(p()),
|
|
164
|
+
setTimeout(() => a(p()), c);
|
|
153
165
|
});
|
|
154
166
|
}
|
|
155
|
-
return Promise.reject(
|
|
167
|
+
return Promise.reject(l);
|
|
156
168
|
});
|
|
157
169
|
return p();
|
|
158
170
|
};
|
|
159
171
|
}
|
|
160
172
|
};
|
|
161
|
-
return new Proxy(
|
|
173
|
+
return new Proxy(v(), n);
|
|
162
174
|
};
|
|
163
|
-
var
|
|
164
|
-
class
|
|
175
|
+
var J = Object.defineProperty, N = (r, e, t) => e in r ? J(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t, C = (r, e, t) => N(r, typeof e != "symbol" ? e + "" : e, t);
|
|
176
|
+
class V {
|
|
165
177
|
// 尾部指针(最新加入的任务)
|
|
166
178
|
constructor(e) {
|
|
167
|
-
if (
|
|
179
|
+
if (C(this, "map"), C(this, "head"), C(this, "tail"), this.map = /* @__PURE__ */ new Map(), this.head = null, this.tail = null, e)
|
|
168
180
|
for (const [t, s] of e)
|
|
169
181
|
this.enqueue(t, s);
|
|
170
182
|
}
|
|
@@ -217,9 +229,9 @@ class N {
|
|
|
217
229
|
return e;
|
|
218
230
|
}
|
|
219
231
|
}
|
|
220
|
-
class
|
|
232
|
+
class H {
|
|
221
233
|
constructor(e = 4) {
|
|
222
|
-
this.parallelCount = e, this.tasks = new
|
|
234
|
+
this.parallelCount = e, this.tasks = new V(), this.runningCount = 0;
|
|
223
235
|
}
|
|
224
236
|
// 加入
|
|
225
237
|
add(e, t) {
|
|
@@ -248,31 +260,31 @@ class $ {
|
|
|
248
260
|
}
|
|
249
261
|
}
|
|
250
262
|
}
|
|
251
|
-
const
|
|
263
|
+
const U = {
|
|
252
264
|
parallelCount: 4,
|
|
253
265
|
retries: 0,
|
|
254
266
|
createId: () => `${Date.now()}_${Math.random().toString().slice(2, 8)}`
|
|
255
267
|
}, F = (r) => {
|
|
256
|
-
const e = { ...
|
|
257
|
-
get(
|
|
258
|
-
return (...
|
|
259
|
-
const
|
|
268
|
+
const e = { ...U, ...r }, { parallelCount: t, createId: s, ...n } = e, o = new H(t), u = n.retries > 0 ? k(n) : null, g = {
|
|
269
|
+
get(h, i) {
|
|
270
|
+
return (...l) => {
|
|
271
|
+
const c = f[i](...l), a = s(c), m = () => u ? u.request(c) : Reflect.apply(h[i], h, l);
|
|
260
272
|
return o.add(a, m);
|
|
261
273
|
};
|
|
262
274
|
}
|
|
263
275
|
};
|
|
264
276
|
return {
|
|
265
|
-
requestor: new Proxy(
|
|
277
|
+
requestor: new Proxy(v(), g),
|
|
266
278
|
concurrentPool: o
|
|
267
279
|
};
|
|
268
|
-
},
|
|
280
|
+
}, W = {
|
|
269
281
|
cacheRequestor: R,
|
|
270
|
-
idempotencyRequestor:
|
|
271
|
-
retryRequestor:
|
|
282
|
+
idempotencyRequestor: _,
|
|
283
|
+
retryRequestor: k,
|
|
272
284
|
concurrentPoolRequestor: F
|
|
273
285
|
};
|
|
274
286
|
export {
|
|
275
287
|
L as inject,
|
|
276
|
-
|
|
277
|
-
|
|
288
|
+
W as requestExtender,
|
|
289
|
+
v as useRequestor
|
|
278
290
|
};
|
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(u,
|
|
1
|
+
(function(u,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(u=typeof globalThis<"u"?globalThis:u||self,l(u["net-vert/core"]={}))})(this,function(u){"use strict";const l={get:(r,e)=>({url:r,method:"get",...e,params:e==null?void 0:e.params}),post:(r,e,t)=>({url:r,method:"post",data:e,headers:{"Content-Type":"application/json",...t==null?void 0:t.headers},...t}),delete:(r,e)=>({url:r,method:"delete",...e}),put:(r,e,t)=>({url:r,method:"put",data:e,headers:{"Content-Type":"application/json",...t==null?void 0:t.headers},...t}),request:r=>r};function M(r){const e={};return Object.keys(l).forEach(t=>{e[t]=(...s)=>{const n=l[t](...s);return r(n)}}),{...e,request:r}}const w="default",x=new Map,j=(r,e=w)=>{x.set(e,M(r))},f=(r=w)=>{const e=x.get(r);if(!e)throw new Error(`Requestor实例 ${r} 未注册`);return e};class b{has(e){return!!localStorage.getItem(e)}get(e){const t=localStorage.getItem(e);if(t)try{return JSON.parse(t)}catch(s){console.error("Error parsing cached data",s);return}}set(e,t){try{const s=JSON.stringify(t);localStorage.setItem(e,s)}catch(s){console.error("Error saving data to localStorage",s)}return t}delete(e){localStorage.removeItem(e)}clear(){localStorage.clear()}}const T=new b,E=new Map,I=r=>r?T:E,O=()=>{const r=new Map;return{getPromise:o=>r.get(o),setPromise:(o,c)=>{r.set(o,c)},delPromise:o=>{r.delete(o)},clearCache:()=>{r.clear()}}},z=(r,e)=>({value:r,expiresAt:Date.now()+e}),$=r=>r.expiresAt>Date.now(),D={key:r=>r.url,persist:!1,duration:1/0},R=r=>{const e={...D,...r},t=I(e.persist),{getPromise:s,setPromise:n,delPromise:o}=O(),c={get(p,i){return async(...h)=>{const d=l[i](...h),a=e.key(d),g=s(a);if(g)return g;const q=t.get(a);let P=!1;if(q&&$(q)){try{P=e.isValid?await e.isValid({key:a,config:d,cachedData:q}):!0}catch(m){console.error(`校验异常 ${a}`,m)}P||t.delete(a)}if(P)return q.value;const k=Reflect.apply(p[i],p,h).then(async m=>{const W=typeof e.duration=="number"?e.duration:e.duration({key:a,config:d,response:m});return t.set(a,z(m,W)),m}).finally(()=>{o(a)});return n(a,k),k}}};return new Proxy(f(),c)},_=r=>{const{method:e,url:t,params:s,data:n}=r;return[e,t,JSON.stringify(s),JSON.stringify(n)].join("|")},A=r=>R({key:e=>r?r(e):_(e),persist:!1}),J={retries:3,delay:0,retryCondition:()=>!0},S=r=>{const{retries:e,delay:t,retryCondition:s}={...J,...r},n={get(o,c){return(...p)=>{let i=0;const y=()=>Reflect.apply(o[c],o,p).catch(h=>{if(i<e&&s(h)){i++;const d=typeof t=="function"?t(i):t;return new Promise(a=>{setTimeout(()=>a(y()),d)})}return Promise.reject(h)});return y()}}};return new Proxy(f(),n)};var N=Object.defineProperty,V=(r,e,t)=>e in r?N(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,C=(r,e,t)=>V(r,typeof e!="symbol"?e+"":e,t);class H{constructor(e){if(C(this,"map"),C(this,"head"),C(this,"tail"),this.map=new Map,this.head=null,this.tail=null,e)for(const[t,s]of e)this.enqueue(t,s)}enqueue(e,t){this.has(e)&&this.remove(e);const s={id:e,data:t,next:null,prev:this.tail};this.tail?this.tail.next=s:this.head=s,this.tail=s,this.map.set(e,s)}dequeue(){if(!this.head)return null;const e=this.head;return this.head=e.next,this.head?this.head.prev=null:this.tail=null,this.map.delete(e.id),e.data}remove(e){const t=this.map.get(e);return t?(t.prev?t.prev.next=t.next:this.head=t.next,t.next?t.next.prev=t.prev:this.tail=t.prev,this.map.delete(e),!0):!1}getTask(e){var t;return(t=this.map.get(e))==null?void 0:t.data}update(e,t){const s=this.map.get(e);return s?(s.data=t,!0):!1}has(e){return this.map.has(e)}peek(){var e;return((e=this.head)==null?void 0:e.data)??null}clear(){this.map.clear(),this.head=null,this.tail=null}get size(){return this.map.size}get queue(){const e=[];let t=this.head;for(;t;)e.push(t.data),t=t.next;return e}}class U{constructor(e=4){this.parallelCount=e,this.tasks=new H,this.runningCount=0}add(e,t){return console.log("poolinset",e,t),new Promise((s,n)=>{this.tasks.enqueue(e,{task:t,resolve:s,reject:n}),this._run()})}remove(e){this.tasks.remove(e)}execute(e){const{task:t,resolve:s,reject:n}=e;return t().then(s).catch(n).finally(()=>{this.runningCount--,this._run()})}_run(){for(;this.runningCount<this.parallelCount&&this.tasks.size>0;){const e=this.tasks.dequeue();this.runningCount++,this.execute(e)}}}const F={parallelCount:4,retries:0,createId:()=>`${Date.now()}_${Math.random().toString().slice(2,8)}`},L={cacheRequestor:R,idempotencyRequestor:A,retryRequestor:S,concurrentPoolRequestor:r=>{const e={...F,...r},{parallelCount:t,createId:s,...n}=e,o=new U(t),c=n.retries>0?S(n):null,v={get(p,i){return(...h)=>{const d=l[i](...h),a=s(d),g=()=>c?c.request(d):Reflect.apply(p[i],p,h);return o.add(a,g)}}};return{requestor:new Proxy(f(),v),concurrentPool:o}}};u.inject=j,u.requestExtender=L,u.useRequestor=f,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
|