Last active
May 6, 2023 04:50
-
-
Save Explosion-Scratch/40f230387a424ed6b8b06beacc3b671e to your computer and use it in GitHub Desktop.
Memoize fetch calls
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
}); | |
}); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
((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