Skip to content

Instantly share code, notes, and snippets.

@Explosion-Scratch
Last active May 6, 2023 04:50
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Explosion-Scratch/40f230387a424ed6b8b06beacc3b671e to your computer and use it in GitHub Desktop.
Save Explosion-Scratch/40f230387a424ed6b8b06beacc3b671e to your computer and use it in GitHub Desktop.
Memoize fetch calls
var _fetch = window.fetch; //Get the original fetch functionm
window.FETCH_ABORT_CONTROLLER = new AbortController();
//Stop all requests
document.addEventListener("stop-all-requests", () => {
window.FETCH_ABORT_CONTROLLER.abort();
window.FETCH_ABORT_CONTROLLER = new AbortController();
})
//Provide a compare function that returns false to delete that cache entry. Provides info about the cached request to the compare function.
document.addEventListener("clear-fetch-cache", ({compare}) => {
if (!compare){
window.FETCH_CACHE = {};
} else {
for (let url of Object.keys(window.FETCH_CACHE)){
if (!compare(JSON.parse(url))){
delete window.FETCH_CACHE[url];
}
}
}
});
//Edit fetch
window.fetch = (url, opts = {}) => {
if (!window.FETCH_CACHE) {
window.FETCH_CACHE = {};
}
return new Promise((resolve) => {
if (opts.fresh){
return fetch(url, opts).then(resolve);
}
//Dispatch a fetch event
window.dispatchEvent(new Event("fetch"));
/*
Generate a sort of unique key about this fetch request.
GET requests will have `opts.method` and `opts.body` as
undefined, which will be removed by JSON.stringify.
For a fetch call such as this:
fetch("https://apis.explosionscratc.repl.co/google?q=dogs")
the key would be:
"{url: 'https://apis.explosionscratc.repl.co'}"
For a POST/DELETE/PUT request however, the key would also have the opts.method and opts.body (and possibly headers).
*/
var key = JSON.stringify({
url,
method: opts.method,
body: opts.body,
headers: JSON.stringify(opts.headers),
});
//First check for existing cache entries:
if (window.FETCH_CACHE[key]) {
//Important to re-clone the response, otherwise we can't fetch something more than once!
resolve(window.FETCH_CACHE[key].clone());
console.log("Fetched from cache");
return; //Important so we don't fetch anyways!
}
_fetch(url, {signal: window.FETCH_ABORT_CONTROLLER.signal, ...opts}).then(async (res) => {
//Custom handlers
if (window.FETCH_INTERCEPTORS?.length){
for (let handler of window.FETCH_INTERCEPTORS){
res = await handler(res);//Fetch interceptors
}
}
window.FETCH_CACHE[key] = res.clone(); //Store the response in the cache
resolve(res); //Respond with the response of the fetch.
//Dispatch fetch-finished event with request body and options, etc.
let ev = new Event("fetch-finished");
Object.assign(ev, {
...key,
response: res.clone(),
options: opts,
})
window.dispatchEvent(ev);
});
});
};
((window) => {
var _fetch = window.fetch; //Get the original fetch functionm
window.fetch = (url, opts = {}) => {
if (!window.FETCH_CACHE) {
window.FETCH_CACHE = {};
}
return new Promise((resolve) => {
/*
Generate a sort of unique key about this fetch request.
GET requests will have `opts.method` and `opts.body` as
undefined, which will be removed by JSON.stringify.
For a fetch call such as this:
fetch("https://apis.explosionscratc.repl.co/google?q=dogs")
the key would be:
"{url: 'https://apis.explosionscratc.repl.co'}"
For a POST/DELETE/PUT request however, the key would also have the opts.method and opts.body (and possibly headers).
*/
var key = JSON.stringify({
url,
method: opts.method,
body: opts.body,
headers: JSON.stringify(opts.headers),
});
//First check for existing cache entries:
if (window.FETCH_CACHE[key]) {
//Important to re-clone the response, otherwise we can't fetch something more than once!
resolve(window.FETCH_CACHE[key].clone());
console.log("Fetched from cache");
return; //Important so we don't fetch anyways!
}
_fetch(url, opts).then((res) => {
window.FETCH_CACHE[key] = res.clone(); //Store the response in the cache
resolve(res); //Respond with the response of the fetch.
console.log("Fetched new version");
});
});
};
})(globalThis);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment