Skip to content

Instantly share code, notes, and snippets.

@mieky
Last active May 1, 2021
Embed
What would you like to do?
Simple function invocation memoization with Typescript
import * as crypto from "crypto";
type CacheKey = string;
type ExpiryTimestamp = number;
const log = (...args: any[]) => process.env.DEBUG && console.log(...args);
const hashCode = (input: string): string =>
crypto.createHash("sha256").update(input).digest("hex");
/**
* Returns a cache key for an invocation of a function (name + args):
* "handleAppMention__b28c94b2195c8ed259f0b415aaee3f39b0b2920a4537611499fa044956917a21".
*
* @param fn Function being called
* @param args Arguments the function is being called with
* @returns A cache key for a function invocation
*/
const getCacheKey = (fn: Function, args: any[] = []): CacheKey => {
const fnName = fn.name || hashCode(fn.toString());
const argsHash = args.map((a) => hashCode(JSON.stringify(a))).join("__");
return `${fnName}__${argsHash}`;
};
/**
* Memoize the return values returned by a given function.
*
* @param fn Function to memoize
* @param duration Number of milliseconds after which the result is no longer valid (optional)
* @returns A memoized version of the given function
*/
function memoize<T extends Function>(fn: T, duration?: number): T {
const cache: Record<CacheKey, T> = {};
const expiries: Record<CacheKey, ExpiryTimestamp> = {};
const memoized = (...args: any[]): T => {
const cacheKey = getCacheKey(fn, args);
if (cache[cacheKey]) {
if (!expiries[cacheKey] || expiries[cacheKey] > Date.now()) {
log("found entry in cache for", cacheKey);
return cache[cacheKey];
}
log("cache key expired, re-evaluate", cacheKey);
delete expiries[cacheKey];
}
log("fresh run for cache key...", cacheKey);
const result = fn.apply(fn, args);
cache[cacheKey] = result;
if (duration) {
expiries[cacheKey] = new Date(Date.now() + duration).getTime();
}
return result;
};
return <T>(memoized as unknown);
}
export { memoize };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment