Skip to content

Instantly share code, notes, and snippets.

@cpitt
Last active April 12, 2024 07:36
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cpitt/9d3d1a86dc5b21a38602bbd16589e178 to your computer and use it in GitHub Desktop.
Save cpitt/9d3d1a86dc5b21a38602bbd16589e178 to your computer and use it in GitHub Desktop.
Memoize a function using local storage as it's cache
/**
* memoizes a function using localStorage as the cache
* @param {function|Promise} fn function or promise you wish to memoize
* @param {Object} [options] additional configuration
* @param {number} [options.ttl=0] time to live in seconds
* @param {Boolean} [options.backgroundRefresh=false] whether the cache should be refreshed asynchronously,
* Note: new results won't resolve until next execution
* @return {Promise} Promise object represents memoized result
*/
function memoizeLocalStorage(
fn,
options = { ttl: 0, backgroundRefresh: false },
) {
if (!fn.name)
throw new Error('memoizeLocalStorage only accepts non-anonymous functions');
// Fetch localstorage or init new object
const cache = JSON.parse(localStorage.getItem(fn.name) || '{}');
//executes and caches result
async function executeAndCacheFn(fn, args, argsKey) {
const result = await fn(args);
// reset the cache value
cache[fn.name] = {
...cache[fn.name],
[argsKey]: { expiration: Date.now() + options.ttl, result },
};
localStorage.setItem(fn.name, JSON.stringify(cache));
}
return async function() {
// Note: JSON.stringify is non-deterministic,
// consider something like json-stable-stringify to avoid extra cache misses
const argsKey = JSON.stringify(arguments);
if (
!cache[fn.name] ||
!cache[fn.name][argsKey] ||
cache[fn.name][argsKey].expiration <= Date.now()
) {
await executeAndCacheFn(fn, arguments, argsKey);
} else if (options.backgroundRefresh) {
executeAndCacheFn(fn, arguments, argsKey);
}
return cache[fn.name][argsKey].result;
};
}
@vegemite4me
Copy link

Very useful function, well written. I had to make a small change from:

const result = await fn(args);

to

const result = fn.apply(null, args);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment