-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwithFetchAbort.ts
44 lines (35 loc) · 1.43 KB
/
withFetchAbort.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
namespace jo {
export function withFetchAbort<TArgs extends any[]>({
getCancelToken,
}:{
getCancelToken: (...args: TArgs[]) => CancelToken | undefined;
}) {
logger.log(`Added abortability to fetch`);
return <TFn extends FetchFn>(fn: TFn): TFn => ((...args: TArgs) => {
const [url, init] = args;
const cancelToken = getCancelToken(args);
if (!cancelToken) throw new Error("CancelToken is required");
if (init && init.signal) throw new Error("cannot add Abortability, fetch is already aborterable");
logger.log(`Added AbortController to fetch`);
const abortController = new AbortController();
const signal = abortController.signal;
let unsubscribe: (() => void) | undefined;
return new Promise<any>((resolve, reject) => {
if (cancelToken) {
unsubscribe = cancelToken.subscribe(abortError => {
// Reject with custom exception
logger.log("Aborting fetch...");
reject(abortError || new Error("Fetch is cancelled"));
abortController.abort();
});
}
// Start fetching
fn(url, { ...init, signal } as any)
.then(resolve, reject);
// Remark: don't unsubscribe, when calling json, blob, ... the abort also works
}).finally(() => {
if (unsubscribe) unsubscribe(); // If completed an not canceled unsubscribe from CancelToken
});
}) as any;
}
}