-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdedupe.ts
76 lines (67 loc) · 2.31 KB
/
dedupe.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// @ts-ignore
import { joinPath, isAbsoluteURL, buildSortedURL } from 'xior';
import type { XiorPlugin, XiorRequestConfig } from '../types';
export type XiorDedupeOptions = {
/**
* check if we need enable throttle, default only `GET` method or`isGet: true` enable
*/
enableDedupe?: boolean | ((config?: XiorRequestConfig) => boolean);
onDedupe?: (config: XiorRequestConfig) => void;
};
/** @ts-ignore */
declare module 'xior' {
interface XiorRequestConfig extends Omit<XiorDedupeOptions, 'dedupeCache'> {
//
}
}
export const inflight = new Map<string, any[]>();
/*
* Prevents having multiple identical requests on the fly at the same time.
*/
export default function xiorDedupePlugin(options: XiorDedupeOptions = {}): XiorPlugin {
const { enableDedupe: _enableDedupe, onDedupe: _onDedupe } = options;
return function (adapter) {
return async (config) => {
const {
paramsSerializer,
enableDedupe = _enableDedupe,
onDedupe = _onDedupe,
} = config as XiorDedupeOptions & XiorRequestConfig;
const isGet = config.method === 'GET' || config.isGet;
const t = typeof enableDedupe;
let enabled: boolean | undefined = undefined;
if (t === 'function') {
enabled = (enableDedupe as (config: XiorRequestConfig) => boolean | undefined)(config);
}
if (enabled === undefined) {
enabled = t === 'undefined' ? isGet : Boolean(enableDedupe);
}
if (!enabled) {
return adapter(config);
}
const key = buildSortedURL(
config.url && isAbsoluteURL(config.url) ? config.url : joinPath(config.baseURL, config.url),
{ a: config.data, b: config.params },
paramsSerializer as (obj: Record<string, any>) => string
);
if (!inflight.has(key)) {
inflight.set(key, []);
} else {
if (onDedupe) onDedupe(config);
return new Promise((resolve, reject) => {
inflight.get(key)?.push([resolve, reject]);
});
}
try {
const response = await adapter(config);
inflight.get(key)?.forEach(([resolve]) => resolve(response));
inflight.delete(key);
return response;
} catch (error) {
inflight.get(key)?.forEach(([, reject]) => reject(error));
inflight.delete(key);
throw error;
}
};
};
}