Skip to content

Instantly share code, notes, and snippets.

@sungchuni
Last active January 21, 2021 04:03
Show Gist options
  • Save sungchuni/d185a4bd44d627c8eb212a34e1703856 to your computer and use it in GitHub Desktop.
Save sungchuni/d185a4bd44d627c8eb212a34e1703856 to your computer and use it in GitHub Desktop.
http cancellator wrapper, for Axios instance and Fetch.fetch
function httpCancellatorForAxios(fn, axiosInstance) {
const configArgIndices = [
["request", 0],
["get", 1],
["delete", 1],
["head", 1],
["options", 1],
["post", 2],
["put", 2],
["patch", 2],
["getUri", 0]
];
return async function cancellable(...args) {
if (!("Proxy" in window)) {
await import("proxy-polyfill");
}
const {CancelToken, isCancel} = await import("axios");
if (cancellable.cancelSource) {
cancellable.cancelSource.cancel();
cancellable.cancelSource = null;
}
cancellable.cancelSource = CancelToken.source();
const {token: cancelToken} = cancellable.cancelSource;
const originalMethods = new Map();
for (const [methodName, configArgIndex] of configArgIndices) {
const method = axiosInstance[methodName];
const proxiedMethod = new Proxy(method, {
apply(target, thisArg, args) {
const newArgs = Array.from(args);
newArgs.splice(
configArgIndex,
1,
Object.assign({}, args[configArgIndex], {cancelToken})
);
return target.apply(thisArg, newArgs);
}
});
originalMethods.set(methodName, method);
axiosInstance[methodName] = proxiedMethod;
}
try {
const promise = fn.apply(this, args);
for (const [methodName] of configArgIndices) {
axiosInstance[methodName] = originalMethods.get(methodName);
}
const result = await promise;
cancellable.cancelSource = null;
return result;
} catch (err) {
if (!isCancel(err)) {
throw err;
}
}
};
}
function httpCancellatorForFetch(fn) {
return async function cancellable(...args) {
if (!("Proxy" in window)) {
await import("proxy-polyfill");
}
if (cancellable.abortController) {
cancellable.abortController.abort();
cancellable.abortController = null;
}
cancellable.abortController = new AbortController();
const {signal} = cancellable.abortController;
const proxiedFetch = new Proxy(fetch, {
apply(target, thisArg, [resource, init]) {
const newInit = Object.assign({}, init, {signal});
return target.apply(thisArg, [resource, newInit]);
}
});
const properFetch = fetch;
globalThis.fetch = proxiedFetch;
try {
const promise = fn.apply(this, args);
globalThis.fetch = properFetch;
const result = await promise;
cancellable.abortController = null;
return result;
} catch (err) {
throw err;
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment