soon-fetch 3.1.1 → 4.0.0-beta.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 +442 -176
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +208 -78
- package/dist/index.js +1 -1
- package/package.json +9 -5
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
> - 🚀 request race
|
|
14
14
|
> - 📝 response cache
|
|
15
15
|
> - 🔤 automatic serialization of JSON
|
|
16
|
-
> - 📏 .min size less than **
|
|
16
|
+
> - 📏 .min size less than **6K**, smaller after zip
|
|
17
17
|
> - 💡 smart type tips with Typescript
|
|
18
18
|
|
|
19
19
|
- [Example](#example)
|
|
@@ -33,31 +33,28 @@
|
|
|
33
33
|
> [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
|
-
import { createSoon } from "soon-fetch";
|
|
36
|
+
import { createSoon, soonFetch } from "soon-fetch";
|
|
37
|
+
|
|
38
|
+
// 使用 soonFetch 作为基础请求函数
|
|
39
|
+
const request = async <T>(url: string, options?: SoonOptions) => {
|
|
40
|
+
const isGet = !options?.method || options?.method.toLocaleLowerCase() === "get";
|
|
41
|
+
const response = await soonFetch<T>({
|
|
42
|
+
url,
|
|
43
|
+
options,
|
|
44
|
+
baseURL: '/api',
|
|
45
|
+
baseOptions: {
|
|
46
|
+
timeout: 20 * 1000,
|
|
47
|
+
headers: new Headers({
|
|
48
|
+
Authorization: "Bearer " + localStorage.getItem("token"),
|
|
49
|
+
}),
|
|
50
|
+
share: isGet ? true : false,
|
|
51
|
+
staleTime: isGet ? 2 * 1000 : 0,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
return response;
|
|
55
|
+
};
|
|
37
56
|
|
|
38
|
-
const soon = createSoon(
|
|
39
|
-
(url, options) => {
|
|
40
|
-
const isGet = !options?.method || options?.method.toLocaleLowerCase() === "get"
|
|
41
|
-
return {
|
|
42
|
-
baseURL: '/api',
|
|
43
|
-
baseOptions: {
|
|
44
|
-
timeout: 20 * 1000,
|
|
45
|
-
headers: new Headers({
|
|
46
|
-
Authorization: "Bearer " + localStorage.getItem("token"),
|
|
47
|
-
}),
|
|
48
|
-
share: isGet ? true : false,
|
|
49
|
-
staleTime: isGet ? 2 * 1000 : 0,
|
|
50
|
-
},
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
({ parsed }) => {
|
|
54
|
-
return <T>() => {
|
|
55
|
-
return fetch(parsed.url, parsed.options).then((res) =>
|
|
56
|
-
res.json()
|
|
57
|
-
) as Promise<T>;
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
);
|
|
57
|
+
const soon = createSoon(request);
|
|
61
58
|
|
|
62
59
|
/** GET */
|
|
63
60
|
soon.get("/user?id=123");
|
|
@@ -71,7 +68,7 @@ soon.post("/login", { body: { username: "admin", password: "123456" } });
|
|
|
71
68
|
export const login = soon
|
|
72
69
|
.POST("/user/login")
|
|
73
70
|
.Body<{ username: string; password: string }>()
|
|
74
|
-
.
|
|
71
|
+
.Ok<{ token: string }>();
|
|
75
72
|
//the develop tools will have type tips for request and response
|
|
76
73
|
login({ username: "admin", password: "123" }).then((res) => {
|
|
77
74
|
localStorage.setItem("token", res.token);
|
|
@@ -134,7 +131,7 @@ soon.get(url, { staleTime: 1000 * 60 * 5 });
|
|
|
134
131
|
import { useEffect, useRef, useState } from "react";
|
|
135
132
|
|
|
136
133
|
type User = { name: string; job: string };
|
|
137
|
-
const api = soon.GET("/api/users").Query<{ page: number }>().
|
|
134
|
+
const api = soon.GET("/api/users").Query<{ page: number }>().Ok<User[]>();
|
|
138
135
|
export default function App() {
|
|
139
136
|
const refAbort = useRef([]);
|
|
140
137
|
const [list, setList] = useState<User[]>([]);
|
|
@@ -161,18 +158,24 @@ export default function App() {
|
|
|
161
158
|
|
|
162
159
|
```typescript
|
|
163
160
|
//can be GET POST PATCH PUT DELETE
|
|
164
|
-
soon.GET(url:string).Query<Query>().
|
|
165
|
-
soon.POST(url:string).Body<Body>().
|
|
161
|
+
soon.GET(url:string).Query<Query>().Ok<Response>()
|
|
162
|
+
soon.POST(url:string).Body<Body>().Ok<Response>()
|
|
163
|
+
soon.GET(url:string).Options({ timeout: 5000 }).Ok<Response>()
|
|
164
|
+
soon.POST(url:string).Body<Body>().Options({ timeout: 5000 }).Ok<Response>()
|
|
166
165
|
//define an api
|
|
167
|
-
export const getUserInfo = soon.GET("/user/:id").
|
|
166
|
+
export const getUserInfo = soon.GET("/user/:id").Ok();
|
|
168
167
|
//then use in any where
|
|
169
168
|
getUserInfo({ id: 2 }).then((res) => console.log(res));
|
|
169
|
+
//define an api with options
|
|
170
|
+
export const getUserInfoWithOptions = soon.GET("/user/:id").Options({ timeout: 5000 }).Ok();
|
|
171
|
+
//then use in any where
|
|
172
|
+
getUserInfoWithOptions({ id: 2 }).then((res) => console.log(res));
|
|
170
173
|
|
|
171
174
|
//with typescript,
|
|
172
175
|
export const login = soon
|
|
173
176
|
.POST("/user/login")
|
|
174
177
|
.Body<{ username: string; password: string }>()
|
|
175
|
-
.
|
|
178
|
+
.Ok<{ token: string }>();
|
|
176
179
|
//the develop tools will have type tips for request and response
|
|
177
180
|
login({ username: "admin", password: "123" }).then((res) => {
|
|
178
181
|
localStorage.setItem("token", res.token);
|
|
@@ -213,25 +216,32 @@ Create a soon request instance.
|
|
|
213
216
|
|
|
214
217
|
**Parameters:**
|
|
215
218
|
|
|
216
|
-
- `
|
|
217
|
-
- `wrapper`: A wrapper function to handle request logic
|
|
219
|
+
- `request`: A function to handle the actual request, receives url and options, returns a Promise
|
|
218
220
|
|
|
219
|
-
**Returns:** An object containing request method and
|
|
221
|
+
**Returns:** An object containing request method, API methods (GET, POST, PUT, DELETE, PATCH), and shortcut methods (get, post, put, delete, patch, head, options)
|
|
220
222
|
|
|
221
223
|
**Example:**
|
|
222
224
|
|
|
223
|
-
```
|
|
225
|
+
```typescript
|
|
224
226
|
const soon = createSoon(
|
|
225
|
-
(url, options) =>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
return response.json();
|
|
230
|
-
}
|
|
227
|
+
async <T>(url: string, options?: SoonOptions): Promise<T> => {
|
|
228
|
+
const response = await fetch(url, options);
|
|
229
|
+
return response.json();
|
|
230
|
+
}
|
|
231
231
|
);
|
|
232
232
|
|
|
233
233
|
// Usage example
|
|
234
|
-
const data = await soon.get("/api/users");
|
|
234
|
+
const data = await soon.get<{ id: number; name: string }[]> ("/api/users");
|
|
235
|
+
|
|
236
|
+
// Define API with options
|
|
237
|
+
export const login = soon
|
|
238
|
+
.POST("/user/login")
|
|
239
|
+
.Body<{ username: string; password: string }>()
|
|
240
|
+
.Ok<{ token: string }>();
|
|
241
|
+
|
|
242
|
+
login({ username: "admin", password: "123" }).then((res) => {
|
|
243
|
+
localStorage.setItem("token", res.token);
|
|
244
|
+
});
|
|
235
245
|
```
|
|
236
246
|
|
|
237
247
|
#### createShortApi
|
|
@@ -247,18 +257,18 @@ Used to generate type-safe API calling methods, supporting path parameters, quer
|
|
|
247
257
|
|
|
248
258
|
**Example:**
|
|
249
259
|
|
|
250
|
-
```
|
|
260
|
+
```typescript
|
|
251
261
|
const API = createShortApi(
|
|
252
|
-
async (url, method, params, query, body, options) => {
|
|
262
|
+
async <T>(url: string, method: string, params: Record<string, string | number> | undefined, query: any, body: any, options: any): Promise<T> => {
|
|
253
263
|
// Handle request logic
|
|
254
|
-
const _url =
|
|
264
|
+
const { url: _url } = parseUrl(url, { params, query });
|
|
255
265
|
const response = await fetch(_url, { ...options, method, body });
|
|
256
266
|
return response.json();
|
|
257
267
|
}
|
|
258
268
|
);
|
|
259
269
|
|
|
260
270
|
// Usage example
|
|
261
|
-
const getUser = API.GET("/api/users/:id").
|
|
271
|
+
const getUser = API.GET("/api/users/:id").Ok<{ id: number; name: string }>();
|
|
262
272
|
const userData = await getUser({ id: 1 });
|
|
263
273
|
```
|
|
264
274
|
|
|
@@ -275,11 +285,14 @@ Factory function to create shortcut methods.
|
|
|
275
285
|
|
|
276
286
|
**Example:**
|
|
277
287
|
|
|
278
|
-
```
|
|
279
|
-
const methods = createShortMethods(["get", "post"], (method) => {
|
|
280
|
-
return (url, options) =>
|
|
288
|
+
```typescript
|
|
289
|
+
const methods = createShortMethods(["get", "post"] as const, (method) => {
|
|
290
|
+
return async <T>(url: string, options?: SoonOptions): Promise<T> => {
|
|
291
|
+
const response = await fetch(url, { ...options, method });
|
|
292
|
+
return response.json();
|
|
293
|
+
};
|
|
281
294
|
});
|
|
282
|
-
// Usage: methods.get('/api/users')
|
|
295
|
+
// Usage: methods.get<{ id: number; name: string }[]>('/api/users')
|
|
283
296
|
```
|
|
284
297
|
|
|
285
298
|
#### parseUrlOptions
|
|
@@ -294,7 +307,7 @@ Parse URL options.
|
|
|
294
307
|
|
|
295
308
|
**Example:**
|
|
296
309
|
|
|
297
|
-
```
|
|
310
|
+
```typescript
|
|
298
311
|
const [url, options] = parseUrlOptions({
|
|
299
312
|
url: "/api/users/:id",
|
|
300
313
|
options: { params: { id: "123" } },
|
|
@@ -315,9 +328,9 @@ Merge multiple Headers objects.
|
|
|
315
328
|
|
|
316
329
|
**Example:**
|
|
317
330
|
|
|
318
|
-
```
|
|
319
|
-
const headers1 = { "Content-Type": "application/json" };
|
|
320
|
-
const headers2 = { Authorization: "Bearer token" };
|
|
331
|
+
```typescript
|
|
332
|
+
const headers1: HeadersInit = { "Content-Type": "application/json" };
|
|
333
|
+
const headers2: HeadersInit = { Authorization: "Bearer token" };
|
|
321
334
|
const mergedHeaders = mergeHeaders(headers1, headers2);
|
|
322
335
|
```
|
|
323
336
|
|
|
@@ -334,7 +347,7 @@ Merge multiple AbortSignal signals.
|
|
|
334
347
|
|
|
335
348
|
**Example:**
|
|
336
349
|
|
|
337
|
-
```
|
|
350
|
+
```typescript
|
|
338
351
|
const controller1 = new AbortController();
|
|
339
352
|
const controller2 = new AbortController();
|
|
340
353
|
const mergedSignal = mergeSignals(
|
|
@@ -357,8 +370,8 @@ Handle baseURL, path parameters and query parameters to generate complete URL.
|
|
|
357
370
|
|
|
358
371
|
**Example:**
|
|
359
372
|
|
|
360
|
-
```
|
|
361
|
-
const url =
|
|
373
|
+
```typescript
|
|
374
|
+
const { url } = parseUrl("/api/users/:id", {
|
|
362
375
|
params: { id: "123" },
|
|
363
376
|
query: { filter: "active" },
|
|
364
377
|
baseURL: "https://api.example.com",
|
|
@@ -379,7 +392,7 @@ Merge request options, including special handling of headers and signals.
|
|
|
379
392
|
|
|
380
393
|
**Example:**
|
|
381
394
|
|
|
382
|
-
```
|
|
395
|
+
```typescript
|
|
383
396
|
const defaultOptions = {
|
|
384
397
|
timeout: 5000,
|
|
385
398
|
headers: { "Content-Type": "application/json" },
|
|
@@ -404,7 +417,7 @@ Check if body is a plain object, not special types like FormData or Blob.
|
|
|
404
417
|
|
|
405
418
|
**Example:**
|
|
406
419
|
|
|
407
|
-
```
|
|
420
|
+
```typescript
|
|
408
421
|
isBodyJson({ name: "John" }); // true
|
|
409
422
|
isBodyJson(new FormData()); // false
|
|
410
423
|
isBodyJson("string"); // false
|
|
@@ -423,7 +436,7 @@ Generate a unique key value based on the request's URL, method, headers, body, q
|
|
|
423
436
|
|
|
424
437
|
**Example:**
|
|
425
438
|
|
|
426
|
-
```
|
|
439
|
+
```typescript
|
|
427
440
|
const key = genRequestKey({
|
|
428
441
|
url: "/api/users",
|
|
429
442
|
options: { method: "GET", params: { id: 1 } },
|
|
@@ -442,26 +455,40 @@ Used to handle request race conditions, terminating previous requests.
|
|
|
442
455
|
|
|
443
456
|
**Example:**
|
|
444
457
|
|
|
445
|
-
```
|
|
458
|
+
```typescript
|
|
446
459
|
const controller = new AbortController();
|
|
447
|
-
const controllers = [];
|
|
448
|
-
|
|
460
|
+
const controllers: AbortController[] = [];
|
|
461
|
+
// 注意:raceAbort 函数已不再直接导出,而是通过 createRequestStore 使用
|
|
449
462
|
```
|
|
450
463
|
|
|
451
|
-
####
|
|
464
|
+
#### createRequestStore
|
|
465
|
+
|
|
466
|
+
Create request store instance.
|
|
467
|
+
Provides request caching, sharing, and race condition handling.
|
|
452
468
|
|
|
453
|
-
|
|
454
|
-
Provides request result caching function, supports expiration time.
|
|
469
|
+
**Parameters:**
|
|
455
470
|
|
|
456
|
-
|
|
471
|
+
- `options`: Configuration options
|
|
472
|
+
- `maxCacheSize`: Maximum cache size (default: 100000)
|
|
473
|
+
- `checkInterval`: Cache check interval in milliseconds (default: 60000)
|
|
474
|
+
|
|
475
|
+
**Returns:** Request store object with the following methods:
|
|
476
|
+
- `entry(key)`: Get entry for specific request key
|
|
477
|
+
- `dispose()`: Dispose the store and clear intervals
|
|
478
|
+
- `get(key)`: Get request by key
|
|
479
|
+
- `set(key, value)`: Set request by key
|
|
480
|
+
- `remove(key)`: Remove request by key
|
|
481
|
+
- `getAll()`: Get all requests
|
|
482
|
+
- `removeAll()`: Remove all requests
|
|
483
|
+
- `clearCache()`: Clear all cache
|
|
484
|
+
- `clearExpiredCache()`: Clear expired cache
|
|
485
|
+
- `abortAll()`: Abort all requests
|
|
457
486
|
|
|
458
487
|
**Example:**
|
|
459
488
|
|
|
460
|
-
```
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
const data = cache.get("key");
|
|
464
|
-
cache.remove("key");
|
|
489
|
+
```typescript
|
|
490
|
+
const store = createRequestStore({ maxCacheSize: 1000, checkInterval: 30000 });
|
|
491
|
+
// Use store in requests
|
|
465
492
|
```
|
|
466
493
|
|
|
467
494
|
#### deepSort
|
|
@@ -472,33 +499,18 @@ Recursively sort the keys of an object to generate a stable object serialization
|
|
|
472
499
|
**Parameters:**
|
|
473
500
|
|
|
474
501
|
- `obj`: Object to sort
|
|
502
|
+
- `sortArr`: Whether to sort arrays (default: false)
|
|
475
503
|
|
|
476
504
|
**Returns:** Object with sorted keys
|
|
477
505
|
|
|
478
506
|
**Example:**
|
|
479
507
|
|
|
480
|
-
```
|
|
508
|
+
```typescript
|
|
481
509
|
const obj = { b: 2, a: 1, c: { z: 3, y: 2 } };
|
|
482
510
|
const sorted = deepSort(obj);
|
|
483
511
|
// Returns: { a: 1, b: 2, c: { y: 2, z: 3 } }
|
|
484
512
|
```
|
|
485
513
|
|
|
486
|
-
#### createShare
|
|
487
|
-
|
|
488
|
-
Create request sharing instance.
|
|
489
|
-
Used to share the same request to avoid duplicate requests.
|
|
490
|
-
|
|
491
|
-
**Returns:** Sharing object containing get and set methods
|
|
492
|
-
|
|
493
|
-
**Example:**
|
|
494
|
-
|
|
495
|
-
```javascript
|
|
496
|
-
const share = createShare();
|
|
497
|
-
const promise = fetch("/api/data");
|
|
498
|
-
share.set("key", promise);
|
|
499
|
-
const sharedPromise = share.get("key"); // Get the same promise
|
|
500
|
-
```
|
|
501
|
-
|
|
502
514
|
#### createSilentRefresh
|
|
503
515
|
|
|
504
516
|
Create silent refresh instance.
|
|
@@ -512,7 +524,7 @@ Used to handle silent refresh functionality when token expires.
|
|
|
512
524
|
|
|
513
525
|
**Example:**
|
|
514
526
|
|
|
515
|
-
```
|
|
527
|
+
```typescript
|
|
516
528
|
const silentRefresh = createSilentRefresh(async () => {
|
|
517
529
|
// Refresh token logic
|
|
518
530
|
await refreshToken();
|
|
@@ -525,6 +537,37 @@ silentRefresh(
|
|
|
525
537
|
);
|
|
526
538
|
```
|
|
527
539
|
|
|
540
|
+
#### soonFetch
|
|
541
|
+
|
|
542
|
+
A lightweight fetch wrapper with caching, sharing, and race condition handling.
|
|
543
|
+
|
|
544
|
+
**Parameters:**
|
|
545
|
+
|
|
546
|
+
- `config`: Configuration object
|
|
547
|
+
- `url`: Request URL
|
|
548
|
+
- `options`: Request options (SoonOptions)
|
|
549
|
+
- `baseURL`: Base URL
|
|
550
|
+
- `baseOptions`: Base request options
|
|
551
|
+
- `store`: Custom request store
|
|
552
|
+
- `sortRequestKey`: Whether to sort request key
|
|
553
|
+
|
|
554
|
+
**Returns:** Promise that resolves to the response
|
|
555
|
+
|
|
556
|
+
**Example:**
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
const data = await soonFetch<User[]>({
|
|
560
|
+
url: "/api/users",
|
|
561
|
+
options: {
|
|
562
|
+
method: "GET",
|
|
563
|
+
query: { page: 1 },
|
|
564
|
+
share: true,
|
|
565
|
+
staleTime: 5000,
|
|
566
|
+
},
|
|
567
|
+
baseURL: "https://api.example.com",
|
|
568
|
+
});
|
|
569
|
+
```
|
|
570
|
+
|
|
528
571
|
#### parseWithBase
|
|
529
572
|
|
|
530
573
|
Parse base URL configuration.
|
|
@@ -538,7 +581,7 @@ Process baseURL, headers, body and other configuration items to generate final r
|
|
|
538
581
|
|
|
539
582
|
**Example:**
|
|
540
583
|
|
|
541
|
-
```
|
|
584
|
+
```typescript
|
|
542
585
|
const result = parseWithBase({
|
|
543
586
|
url: "/api/users",
|
|
544
587
|
options: { method: "GET" },
|
|
@@ -559,7 +602,7 @@ Used to convert plain objects to FormData format, supports files and regular val
|
|
|
559
602
|
|
|
560
603
|
**Example:**
|
|
561
604
|
|
|
562
|
-
```
|
|
605
|
+
```typescript
|
|
563
606
|
const formData = toFormData({
|
|
564
607
|
name: "John",
|
|
565
608
|
avatar: fileBlob,
|
|
@@ -567,13 +610,103 @@ const formData = toFormData({
|
|
|
567
610
|
});
|
|
568
611
|
```
|
|
569
612
|
|
|
613
|
+
#### progressDownload
|
|
614
|
+
|
|
615
|
+
Download with progress tracking.
|
|
616
|
+
Used to download files with progress updates.
|
|
617
|
+
|
|
618
|
+
**Parameters:**
|
|
619
|
+
|
|
620
|
+
- `response`: Response object
|
|
621
|
+
- `onProgress`: Progress callback function
|
|
622
|
+
|
|
623
|
+
**Returns:** Promise that resolves to ArrayBuffer
|
|
624
|
+
|
|
625
|
+
**Example:**
|
|
626
|
+
|
|
627
|
+
```typescript
|
|
628
|
+
const response = await fetch("/api/download");
|
|
629
|
+
const buffer = await progressDownload(response, (progress, downloaded, total) => {
|
|
630
|
+
console.log(`Progress: ${progress}%, Downloaded: ${downloaded}/${total}`);
|
|
631
|
+
});
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
#### progressReadBody
|
|
635
|
+
|
|
636
|
+
Read response body with progress tracking.
|
|
637
|
+
Used to read response bodies with progress updates.
|
|
638
|
+
|
|
639
|
+
**Parameters:**
|
|
640
|
+
|
|
641
|
+
- `body`: ReadableStream<Uint8Array>
|
|
642
|
+
- `onProgress`: Progress callback function
|
|
643
|
+
- `total`: Total size in bytes (default: 0)
|
|
644
|
+
|
|
645
|
+
**Returns:** Promise that resolves to ArrayBuffer
|
|
646
|
+
|
|
647
|
+
**Example:**
|
|
648
|
+
|
|
649
|
+
```typescript
|
|
650
|
+
const response = await fetch("/api/download");
|
|
651
|
+
const buffer = await progressReadBody(response.body!, (progress, downloaded, total) => {
|
|
652
|
+
console.log(`Progress: ${progress}%, Downloaded: ${downloaded}/${total}`);
|
|
653
|
+
});
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
#### parseOptions
|
|
657
|
+
|
|
658
|
+
Parse and merge request options.
|
|
659
|
+
Used to process request options, including baseURL, headers, and body.
|
|
660
|
+
|
|
661
|
+
**Parameters:**
|
|
662
|
+
|
|
663
|
+
- `urlOptions`: Object containing url, options, baseURL, and baseOptions
|
|
664
|
+
|
|
665
|
+
**Returns:** Object containing parsed url, options, is_body_json, and abortController
|
|
666
|
+
|
|
667
|
+
**Example:**
|
|
668
|
+
|
|
669
|
+
```typescript
|
|
670
|
+
const parsed = parseOptions({
|
|
671
|
+
url: "/api/users",
|
|
672
|
+
options: { method: "GET", query: { page: 1 } },
|
|
673
|
+
baseURL: "https://api.example.com",
|
|
674
|
+
baseOptions: { timeout: 5000 },
|
|
675
|
+
});
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
#### requestWithStore
|
|
679
|
+
|
|
680
|
+
Request wrapper with store support.
|
|
681
|
+
Used to handle requests with caching, sharing, and race condition handling.
|
|
682
|
+
|
|
683
|
+
**Parameters:**
|
|
684
|
+
|
|
685
|
+
- `store`: Request store instance
|
|
686
|
+
- `requestFn`: Request function
|
|
687
|
+
- `requestKey`: Request key
|
|
688
|
+
- `fetchAbort`: AbortController
|
|
689
|
+
- `options`: Options object
|
|
690
|
+
|
|
691
|
+
**Returns:** Promise that resolves to the response
|
|
692
|
+
|
|
693
|
+
**Example:**
|
|
694
|
+
|
|
695
|
+
```typescript
|
|
696
|
+
const store = createRequestStore();
|
|
697
|
+
const data = await requestWithStore(store, () => fetch(url, options), requestKey, abortController, {
|
|
698
|
+
share: true,
|
|
699
|
+
staleTime: 5000,
|
|
700
|
+
});
|
|
701
|
+
```
|
|
702
|
+
|
|
570
703
|
[English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
|
|
571
704
|
|
|
572
705
|
<!-- omit in toc -->
|
|
573
706
|
|
|
574
707
|
#### soon-fetch
|
|
575
708
|
|
|
576
|
-
**极轻量的请求库,不到
|
|
709
|
+
**极轻量的请求库,不到 6K**
|
|
577
710
|
|
|
578
711
|
> - 🌐 自动解析 rest Url 的参数
|
|
579
712
|
> - ⭐ 快捷定义请求 api
|
|
@@ -582,7 +715,7 @@ const formData = toFormData({
|
|
|
582
715
|
> - 🚀 请求竞态
|
|
583
716
|
> - 📝 响应缓存
|
|
584
717
|
> - 🔤 自动处理 JSON
|
|
585
|
-
> - 📏 不到 **
|
|
718
|
+
> - 📏 不到 **6K** , zip 后会更小
|
|
586
719
|
> - 💡 用 typescript 有智能类型提醒
|
|
587
720
|
|
|
588
721
|
- [示例](#示例)
|
|
@@ -605,29 +738,28 @@ const formData = toFormData({
|
|
|
605
738
|
> [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)
|
|
606
739
|
|
|
607
740
|
```typescript
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
);
|
|
741
|
+
import { createSoon, soonFetch } from "soon-fetch";
|
|
742
|
+
|
|
743
|
+
// 使用 soonFetch 作为基础请求函数
|
|
744
|
+
const request = async <T>(url: string, options?: SoonOptions) => {
|
|
745
|
+
const isGet = !options?.method || options?.method.toLocaleLowerCase() === "get";
|
|
746
|
+
const response = await soonFetch<T>({
|
|
747
|
+
url,
|
|
748
|
+
options,
|
|
749
|
+
baseURL: '/api',
|
|
750
|
+
baseOptions: {
|
|
751
|
+
timeout: 20 * 1000,
|
|
752
|
+
headers: new Headers({
|
|
753
|
+
Authorization: "Bearer " + localStorage.getItem("token"),
|
|
754
|
+
}),
|
|
755
|
+
share: isGet ? true : false,
|
|
756
|
+
staleTime: isGet ? 2 * 1000 : 0,
|
|
757
|
+
},
|
|
758
|
+
});
|
|
759
|
+
return response;
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
const soon = createSoon(request);
|
|
631
763
|
|
|
632
764
|
/** GET */
|
|
633
765
|
soon.get("/user?id=123");
|
|
@@ -641,7 +773,7 @@ soon.post("/login", { body: { username: "admin", password: "123456" } });
|
|
|
641
773
|
export const login = soon
|
|
642
774
|
.POST("/user/login")
|
|
643
775
|
.Body<{ username: string; password: string }>()
|
|
644
|
-
.
|
|
776
|
+
.Ok<{ token: string }>();
|
|
645
777
|
|
|
646
778
|
//开发工具会有请求和响应的智能提醒
|
|
647
779
|
login({ username: "admin", password: "123" }).then((res) => {
|
|
@@ -705,7 +837,7 @@ soon.get(url, { staleTime: 1000 * 60 * 5 });
|
|
|
705
837
|
import { useEffect, useRef, useState } from "react";
|
|
706
838
|
|
|
707
839
|
type User = { name: string; job: string };
|
|
708
|
-
const api = soon.GET("/api/users").Query<{ page: number }>().
|
|
840
|
+
const api = soon.GET("/api/users").Query<{ page: number }>().Ok<User[]>();
|
|
709
841
|
export default function App() {
|
|
710
842
|
const refAbort = useRef([]);
|
|
711
843
|
const [list, setList] = useState<User[]>([]);
|
|
@@ -733,19 +865,25 @@ export default function App() {
|
|
|
733
865
|
```ts
|
|
734
866
|
//可以是 GET POST PATCH PUT DELETE
|
|
735
867
|
//GET 请求数据传递至query,其他方法请求数据传递至body
|
|
736
|
-
soon.GET(url:string).Query<Query>().
|
|
737
|
-
soon.POST(url:string).Body<Body>().
|
|
868
|
+
soon.GET(url:string).Query<Query>().Ok<Response>()
|
|
869
|
+
soon.POST(url:string).Body<Body>().Ok<Response>()
|
|
870
|
+
soon.GET(url:string).Options({ timeout: 5000 }).Ok<Response>()
|
|
871
|
+
soon.POST(url:string).Body<Body>().Options({ timeout: 5000 }).Ok<Response>()
|
|
738
872
|
|
|
739
873
|
//定义一个api
|
|
740
|
-
export const getUserInfo=soon.GET('/user/:id').
|
|
874
|
+
export const getUserInfo=soon.GET('/user/:id').Ok()
|
|
741
875
|
//使用
|
|
742
876
|
getUserInfo({id:2}).then(res=>console.log(res))
|
|
877
|
+
//定义一个带选项的api
|
|
878
|
+
export const getUserInfoWithOptions=soon.GET('/user/:id').Options({ timeout: 5000 }).Ok()
|
|
879
|
+
//使用
|
|
880
|
+
getUserInfoWithOptions({id:2}).then(res=>console.log(res))
|
|
743
881
|
|
|
744
882
|
//用typescript,
|
|
745
883
|
export const login=soon
|
|
746
884
|
.POST('/user/login')
|
|
747
885
|
.Body<{username:string,password:string}>()
|
|
748
|
-
.
|
|
886
|
+
.Ok<{token:string}>()
|
|
749
887
|
//开发工具会有请求和响应的智能提醒
|
|
750
888
|
login({username:'admin',password:'123'}).then(res=>{
|
|
751
889
|
localStorage.setItem('token', res.token);
|
|
@@ -786,24 +924,32 @@ type SoonOptions = Omit<RequestInit, "body"> & {
|
|
|
786
924
|
|
|
787
925
|
**参数:**
|
|
788
926
|
|
|
789
|
-
- `
|
|
790
|
-
- `wrapper`: 包装器函数,用于处理请求逻辑
|
|
927
|
+
- `request`: 用于处理实际请求的函数,接收 url 和 options,返回一个 Promise
|
|
791
928
|
|
|
792
|
-
**返回:** 包含 request
|
|
929
|
+
**返回:** 包含 request 方法、API 方法(GET、POST、PUT、DELETE、PATCH)和快捷方法(get、post、put、delete、patch、head、options)的对象
|
|
793
930
|
|
|
794
931
|
**示例:**
|
|
795
932
|
|
|
796
|
-
```
|
|
933
|
+
```typescript
|
|
797
934
|
const soon = createSoon(
|
|
798
|
-
(url, options) =>
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
return response.json();
|
|
803
|
-
}
|
|
935
|
+
async (url, options) => {
|
|
936
|
+
const response = await fetch(url, options);
|
|
937
|
+
return response.json();
|
|
938
|
+
}
|
|
804
939
|
);
|
|
940
|
+
|
|
805
941
|
// 使用示例
|
|
806
942
|
const data = await soon.get("/api/users");
|
|
943
|
+
|
|
944
|
+
// 定义带选项的 API
|
|
945
|
+
export const login = soon
|
|
946
|
+
.POST("/user/login")
|
|
947
|
+
.Body<{ username: string; password: string }>()
|
|
948
|
+
.Ok<{ token: string }>();
|
|
949
|
+
|
|
950
|
+
login({ username: "admin", password: "123" }).then((res) => {
|
|
951
|
+
localStorage.setItem("token", res.token);
|
|
952
|
+
});
|
|
807
953
|
```
|
|
808
954
|
|
|
809
955
|
#### createShortApi
|
|
@@ -819,7 +965,7 @@ const data = await soon.get("/api/users");
|
|
|
819
965
|
|
|
820
966
|
**示例:**
|
|
821
967
|
|
|
822
|
-
```
|
|
968
|
+
```typescript
|
|
823
969
|
const API = createShortApi(
|
|
824
970
|
async (url, method, params, query, body, options) => {
|
|
825
971
|
// 处理请求逻辑
|
|
@@ -830,7 +976,7 @@ const API = createShortApi(
|
|
|
830
976
|
);
|
|
831
977
|
|
|
832
978
|
// 使用示例
|
|
833
|
-
const getUser = API.GET("/api/users/:id").
|
|
979
|
+
const getUser = API.GET("/api/users/:id").Ok();
|
|
834
980
|
const userData = await getUser({ id: 1 });
|
|
835
981
|
```
|
|
836
982
|
|
|
@@ -847,8 +993,8 @@ const userData = await getUser({ id: 1 });
|
|
|
847
993
|
|
|
848
994
|
**示例:**
|
|
849
995
|
|
|
850
|
-
```
|
|
851
|
-
const methods = createShortMethods(["get", "post"], (method) => {
|
|
996
|
+
```typescript
|
|
997
|
+
const methods = createShortMethods(["get", "post"] as const, (method) => {
|
|
852
998
|
return (url, options) => fetch(url, { ...options, method });
|
|
853
999
|
});
|
|
854
1000
|
// 使用: methods.get('/api/users')
|
|
@@ -866,7 +1012,7 @@ const methods = createShortMethods(["get", "post"], (method) => {
|
|
|
866
1012
|
|
|
867
1013
|
**示例:**
|
|
868
1014
|
|
|
869
|
-
```
|
|
1015
|
+
```typescript
|
|
870
1016
|
const [url, options] = parseUrlOptions({
|
|
871
1017
|
url: "/api/users/:id",
|
|
872
1018
|
options: { params: { id: "123" } },
|
|
@@ -887,9 +1033,9 @@ const [url, options] = parseUrlOptions({
|
|
|
887
1033
|
|
|
888
1034
|
**示例:**
|
|
889
1035
|
|
|
890
|
-
```
|
|
891
|
-
const headers1 = { "Content-Type": "application/json" };
|
|
892
|
-
const headers2 = { Authorization: "Bearer token" };
|
|
1036
|
+
```typescript
|
|
1037
|
+
const headers1: HeadersInit = { "Content-Type": "application/json" };
|
|
1038
|
+
const headers2: HeadersInit = { Authorization: "Bearer token" };
|
|
893
1039
|
const mergedHeaders = mergeHeaders(headers1, headers2);
|
|
894
1040
|
```
|
|
895
1041
|
|
|
@@ -906,7 +1052,7 @@ const mergedHeaders = mergeHeaders(headers1, headers2);
|
|
|
906
1052
|
|
|
907
1053
|
**示例:**
|
|
908
1054
|
|
|
909
|
-
```
|
|
1055
|
+
```typescript
|
|
910
1056
|
const controller1 = new AbortController();
|
|
911
1057
|
const controller2 = new AbortController();
|
|
912
1058
|
const mergedSignal = mergeSignals(
|
|
@@ -929,7 +1075,7 @@ const mergedSignal = mergeSignals(
|
|
|
929
1075
|
|
|
930
1076
|
**示例:**
|
|
931
1077
|
|
|
932
|
-
```
|
|
1078
|
+
```typescript
|
|
933
1079
|
const url = mergeUrl("/api/users/:id", {
|
|
934
1080
|
params: { id: "123" },
|
|
935
1081
|
query: { filter: "active" },
|
|
@@ -951,7 +1097,7 @@ const url = mergeUrl("/api/users/:id", {
|
|
|
951
1097
|
|
|
952
1098
|
**示例:**
|
|
953
1099
|
|
|
954
|
-
```
|
|
1100
|
+
```typescript
|
|
955
1101
|
const defaultOptions = {
|
|
956
1102
|
timeout: 5000,
|
|
957
1103
|
headers: { "Content-Type": "application/json" },
|
|
@@ -976,7 +1122,7 @@ const mergedOptions = mergeOptions(defaultOptions, requestOptions);
|
|
|
976
1122
|
|
|
977
1123
|
**示例:**
|
|
978
1124
|
|
|
979
|
-
```
|
|
1125
|
+
```typescript
|
|
980
1126
|
isBodyJson({ name: "John" }); // true
|
|
981
1127
|
isBodyJson(new FormData()); // false
|
|
982
1128
|
isBodyJson("string"); // false
|
|
@@ -995,7 +1141,7 @@ isBodyJson("string"); // false
|
|
|
995
1141
|
|
|
996
1142
|
**示例:**
|
|
997
1143
|
|
|
998
|
-
```
|
|
1144
|
+
```typescript
|
|
999
1145
|
const key = genRequestKey({
|
|
1000
1146
|
url: "/api/users",
|
|
1001
1147
|
options: { method: "GET", params: { id: 1 } },
|
|
@@ -1014,26 +1160,40 @@ const key = genRequestKey({
|
|
|
1014
1160
|
|
|
1015
1161
|
**示例:**
|
|
1016
1162
|
|
|
1017
|
-
```
|
|
1163
|
+
```typescript
|
|
1018
1164
|
const controller = new AbortController();
|
|
1019
1165
|
const controllers = [];
|
|
1020
1166
|
raceAbort(controller, controllers); // 终止之前的请求并添加当前控制器
|
|
1021
1167
|
```
|
|
1022
1168
|
|
|
1023
|
-
####
|
|
1169
|
+
#### createRequestStore
|
|
1024
1170
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1171
|
+
创建请求存储实例。
|
|
1172
|
+
提供请求缓存、共享和竞态条件处理。
|
|
1027
1173
|
|
|
1028
|
-
|
|
1174
|
+
**参数:**
|
|
1175
|
+
|
|
1176
|
+
- `options`: 配置选项
|
|
1177
|
+
- `maxCacheSize`: 最大缓存大小(默认: 100000)
|
|
1178
|
+
- `checkInterval`: 缓存检查间隔(毫秒,默认: 60000)
|
|
1179
|
+
|
|
1180
|
+
**返回:** 请求存储对象,包含以下方法:
|
|
1181
|
+
- `entry(key)`: 获取特定请求键的条目
|
|
1182
|
+
- `dispose()`: 销毁存储并清除定时器
|
|
1183
|
+
- `get(key)`: 根据键获取请求
|
|
1184
|
+
- `set(key, value)`: 根据键设置请求
|
|
1185
|
+
- `remove(key)`: 根据键移除请求
|
|
1186
|
+
- `getAll()`: 获取所有请求
|
|
1187
|
+
- `removeAll()`: 移除所有请求
|
|
1188
|
+
- `clearCache()`: 清除所有缓存
|
|
1189
|
+
- `clearExpiredCache()`: 清除过期缓存
|
|
1190
|
+
- `abortAll()`: 中止所有请求
|
|
1029
1191
|
|
|
1030
1192
|
**示例:**
|
|
1031
1193
|
|
|
1032
|
-
```
|
|
1033
|
-
const
|
|
1034
|
-
|
|
1035
|
-
const data = cache.get("key");
|
|
1036
|
-
cache.remove("key");
|
|
1194
|
+
```typescript
|
|
1195
|
+
const store = createRequestStore({ maxCacheSize: 1000, checkInterval: 30000 });
|
|
1196
|
+
// 在请求中使用 store
|
|
1037
1197
|
```
|
|
1038
1198
|
|
|
1039
1199
|
#### deepSort
|
|
@@ -1044,33 +1204,18 @@ cache.remove("key");
|
|
|
1044
1204
|
**参数:**
|
|
1045
1205
|
|
|
1046
1206
|
- `obj`: 要排序的对象
|
|
1207
|
+
- `sortArr`: 是否对数组进行排序(默认: false)
|
|
1047
1208
|
|
|
1048
1209
|
**返回:** 键排序后的对象
|
|
1049
1210
|
|
|
1050
1211
|
**示例:**
|
|
1051
1212
|
|
|
1052
|
-
```
|
|
1213
|
+
```typescript
|
|
1053
1214
|
const obj = { b: 2, a: 1, c: { z: 3, y: 2 } };
|
|
1054
1215
|
const sorted = deepSort(obj);
|
|
1055
1216
|
// 返回: { a: 1, b: 2, c: { y: 2, z: 3 } }
|
|
1056
1217
|
```
|
|
1057
1218
|
|
|
1058
|
-
#### createShare
|
|
1059
|
-
|
|
1060
|
-
创建请求共享实例。
|
|
1061
|
-
用于共享相同请求,避免重复请求。
|
|
1062
|
-
|
|
1063
|
-
**返回:** 包含 get 和 set 方法的共享对象
|
|
1064
|
-
|
|
1065
|
-
**示例:**
|
|
1066
|
-
|
|
1067
|
-
```javascript
|
|
1068
|
-
const share = createShare();
|
|
1069
|
-
const promise = fetch("/api/data");
|
|
1070
|
-
share.set("key", promise);
|
|
1071
|
-
const sharedPromise = share.get("key"); // 获取相同 promise
|
|
1072
|
-
```
|
|
1073
|
-
|
|
1074
1219
|
#### createSilentRefresh
|
|
1075
1220
|
|
|
1076
1221
|
创建静默刷新实例。
|
|
@@ -1084,7 +1229,7 @@ const sharedPromise = share.get("key"); // 获取相同 promise
|
|
|
1084
1229
|
|
|
1085
1230
|
**示例:**
|
|
1086
1231
|
|
|
1087
|
-
```
|
|
1232
|
+
```typescript
|
|
1088
1233
|
const silentRefresh = createSilentRefresh(async () => {
|
|
1089
1234
|
// 刷新token逻辑
|
|
1090
1235
|
await refreshToken();
|
|
@@ -1097,6 +1242,37 @@ silentRefresh(
|
|
|
1097
1242
|
);
|
|
1098
1243
|
```
|
|
1099
1244
|
|
|
1245
|
+
#### soonFetch
|
|
1246
|
+
|
|
1247
|
+
一个轻量级的 fetch 包装器,支持缓存、共享和竞态条件处理。
|
|
1248
|
+
|
|
1249
|
+
**参数:**
|
|
1250
|
+
|
|
1251
|
+
- `config`: 配置对象
|
|
1252
|
+
- `url`: 请求 URL
|
|
1253
|
+
- `options`: 请求选项 (SoonOptions)
|
|
1254
|
+
- `baseURL`: 基础 URL
|
|
1255
|
+
- `baseOptions`: 基础请求选项
|
|
1256
|
+
- `store`: 自定义请求存储
|
|
1257
|
+
- `sortRequestKey`: 是否对请求键进行排序
|
|
1258
|
+
|
|
1259
|
+
**返回:** 解析为响应的 Promise
|
|
1260
|
+
|
|
1261
|
+
**示例:**
|
|
1262
|
+
|
|
1263
|
+
```typescript
|
|
1264
|
+
const data = await soonFetch<User[]>({
|
|
1265
|
+
url: "/api/users",
|
|
1266
|
+
options: {
|
|
1267
|
+
method: "GET",
|
|
1268
|
+
query: { page: 1 },
|
|
1269
|
+
share: true,
|
|
1270
|
+
staleTime: 5000,
|
|
1271
|
+
},
|
|
1272
|
+
baseURL: "https://api.example.com",
|
|
1273
|
+
});
|
|
1274
|
+
```
|
|
1275
|
+
|
|
1100
1276
|
#### parseWithBase
|
|
1101
1277
|
|
|
1102
1278
|
解析基础 URL 配置。
|
|
@@ -1110,7 +1286,7 @@ silentRefresh(
|
|
|
1110
1286
|
|
|
1111
1287
|
**示例:**
|
|
1112
1288
|
|
|
1113
|
-
```
|
|
1289
|
+
```typescript
|
|
1114
1290
|
const result = parseWithBase({
|
|
1115
1291
|
url: "/api/users",
|
|
1116
1292
|
options: { method: "GET" },
|
|
@@ -1131,7 +1307,7 @@ const result = parseWithBase({
|
|
|
1131
1307
|
|
|
1132
1308
|
**示例:**
|
|
1133
1309
|
|
|
1134
|
-
```
|
|
1310
|
+
```typescript
|
|
1135
1311
|
const formData = toFormData({
|
|
1136
1312
|
name: "John",
|
|
1137
1313
|
avatar: fileBlob,
|
|
@@ -1139,6 +1315,96 @@ const formData = toFormData({
|
|
|
1139
1315
|
});
|
|
1140
1316
|
```
|
|
1141
1317
|
|
|
1318
|
+
#### progressDownload
|
|
1319
|
+
|
|
1320
|
+
带进度的下载。
|
|
1321
|
+
用于下载文件并跟踪进度。
|
|
1322
|
+
|
|
1323
|
+
**参数:**
|
|
1324
|
+
|
|
1325
|
+
- `response`: 响应对象
|
|
1326
|
+
- `onProgress`: 进度回调函数
|
|
1327
|
+
|
|
1328
|
+
**返回:** 解析为 ArrayBuffer 的 Promise
|
|
1329
|
+
|
|
1330
|
+
**示例:**
|
|
1331
|
+
|
|
1332
|
+
```typescript
|
|
1333
|
+
const response = await fetch("/api/download");
|
|
1334
|
+
const buffer = await progressDownload(response, (progress, downloaded, total) => {
|
|
1335
|
+
console.log(`进度: ${progress}%, 已下载: ${downloaded}/${total}`);
|
|
1336
|
+
});
|
|
1337
|
+
```
|
|
1338
|
+
|
|
1339
|
+
#### progressReadBody
|
|
1340
|
+
|
|
1341
|
+
带进度的读取响应体。
|
|
1342
|
+
用于读取响应体并跟踪进度。
|
|
1343
|
+
|
|
1344
|
+
**参数:**
|
|
1345
|
+
|
|
1346
|
+
- `body`: ReadableStream<Uint8Array>
|
|
1347
|
+
- `onProgress`: 进度回调函数
|
|
1348
|
+
- `total`: 总大小(字节,默认: 0)
|
|
1349
|
+
|
|
1350
|
+
**返回:** 解析为 ArrayBuffer 的 Promise
|
|
1351
|
+
|
|
1352
|
+
**示例:**
|
|
1353
|
+
|
|
1354
|
+
```typescript
|
|
1355
|
+
const response = await fetch("/api/download");
|
|
1356
|
+
const buffer = await progressReadBody(response.body, (progress, downloaded, total) => {
|
|
1357
|
+
console.log(`进度: ${progress}%, 已下载: ${downloaded}/${total}`);
|
|
1358
|
+
});
|
|
1359
|
+
```
|
|
1360
|
+
|
|
1361
|
+
#### parseOptions
|
|
1362
|
+
|
|
1363
|
+
解析和合并请求选项。
|
|
1364
|
+
用于处理请求选项,包括 baseURL、headers 和 body。
|
|
1365
|
+
|
|
1366
|
+
**参数:**
|
|
1367
|
+
|
|
1368
|
+
- `urlOptions`: 包含 url、options、baseURL 和 baseOptions 的对象
|
|
1369
|
+
|
|
1370
|
+
**返回:** 包含解析后的 url、options、is_body_json 和 abortController 的对象
|
|
1371
|
+
|
|
1372
|
+
**示例:**
|
|
1373
|
+
|
|
1374
|
+
```typescript
|
|
1375
|
+
const parsed = parseOptions({
|
|
1376
|
+
url: "/api/users",
|
|
1377
|
+
options: { method: "GET", query: { page: 1 } },
|
|
1378
|
+
baseURL: "https://api.example.com",
|
|
1379
|
+
baseOptions: { timeout: 5000 },
|
|
1380
|
+
});
|
|
1381
|
+
```
|
|
1382
|
+
|
|
1383
|
+
#### requestWithStore
|
|
1384
|
+
|
|
1385
|
+
带存储支持的请求包装器。
|
|
1386
|
+
用于处理带有缓存、共享和竞态条件处理的请求。
|
|
1387
|
+
|
|
1388
|
+
**参数:**
|
|
1389
|
+
|
|
1390
|
+
- `store`: 请求存储实例
|
|
1391
|
+
- `requestFn`: 请求函数
|
|
1392
|
+
- `requestKey`: 请求键
|
|
1393
|
+
- `fetchAbort`: AbortController
|
|
1394
|
+
- `options`: 选项对象
|
|
1395
|
+
|
|
1396
|
+
**返回:** 解析为响应的 Promise
|
|
1397
|
+
|
|
1398
|
+
**示例:**
|
|
1399
|
+
|
|
1400
|
+
```typescript
|
|
1401
|
+
const store = createRequestStore();
|
|
1402
|
+
const data = await requestWithStore(store, () => fetch(url, options), requestKey, abortController, {
|
|
1403
|
+
share: true,
|
|
1404
|
+
staleTime: 5000,
|
|
1405
|
+
});
|
|
1406
|
+
```
|
|
1407
|
+
|
|
1142
1408
|
|
|
1143
1409
|
[English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
|
|
1144
1410
|
|