fast-typescript-memoize: fast memoization decorator and other helpers with 1st class support for Promises
@Memoize() decorator
A @Memoize()
TypeScript decorator similar to
typescript-memoize.
Differences:
- If used to memoize async functions, it clears the memoize cache if the
promise gets rejected (i.e. it doesn't memoize exceptions in async
functions).
- Stronger typing for internal code.
- Does not support any notion of expiration.
import { Memoize } from "fast-typescript-memoize";
class Class {
private count = 0;
@Memoize()
method0() {
return count++;
}
@Memoize()
method1(arg: string) {
return count++;
}
@Memoize((arg1: string, arg2: number) => `${arg1}#${arg2}`)
method2(arg1: string, arg2: number) {
return count++;
}
@Memoize()
asyncMethod(arg: string) {
count++;
if (arg == "ouch") {
throw "ouch";
}
}
}
const obj = new Class();
obj.method0();
obj.method0();
obj.method1("abc");
obj.method1("abc");
obj.method1("def");
obj.method2("abc", 42);
obj.method2("abc", 42);
await asyncMethod("ok");
await asyncMethod("ok");
await asyncMethod("ouch");
await asyncMethod("ouch");
memoize0(obj, tag, func) helper
Saves the value returned by func()
in a hidden property tag
(typically a
symbol) of obj
object, so next time memoize0() is called, that value will be
returned, and func
won't be called.
The main goal is performance and simplicity.
import { memoize0 } from "fast-typescript-memoize";
let count = 0;
const $tag = Symbol("$tag");
const obj = {};
memoize0(obj, $tag, () => count++);
memoize0(obj, $tag, () => count++);
memoize2(obj, tag, func) helper
A simple intrusive 1-slot cache memoization helper for 2 parameters func
. It's
useful when we have a very high chance of hitrate. The helper is faster (and
more memory efficient) than a Map<TArg1, Map<TArg2, TResult>>
based approach
since it doesn't create intermediate maps.
This method works seamlessly for async functions too: the returned Promise is
eagerly memoized, so all the callers will subscribe to the same Promise.
Returns the new memoized function with 2 arguments for the tag
.
let count = 0;
const $tag = Symbol("$tag");
const obj = {};
memoize2(obj, $tag, (arg1, arg2) => count++)("abc", 42);
memoize2(obj, $tag, (arg1, arg2) => count++)("abc", 42);
memoize2(obj, $tag, (arg1, arg2) => count++)("xyz", 101);
memoize2(obj, $tag, (arg1, arg2) => count++)("abc", 42);
memoizeExpireUnused(func, { resolve, unusedMs })
Similar to lodash.memoize(), but
auto-expires (and removes from memory) the cached results after the provided
number of inactive milliseconds. Each time we read a cached result, the
expiration timer starts from scratch.
This function is more expensive than lodash.memoize()
, because it uses a JS
timer under the hood.
let count = 0;
const func = memoizeExpireUnused((s) => count++, { resolver: (s) => s, unusedMs: 1000 });
func("a");
func("a");
... after 2 seconds, memory for the cached result is freed ...
func("a");