An ES7 decorator for memoising (caching) a method's response
npm install @aloreljs/memoise-decorator
Symbol
construction via Symbol('someName')
& Map
s must be available.
- Typescript - full
- Spec-compliant decorator proposal - full
- Babel (current proposal) - full
- Babel (legacy) - full
import {Memoise} from '@aloreljs/memoise-decorator';
class MyClass {
@Memoise()
someMethod(a, b, c) {
}
@Memoise()
static someStaticMethod(a, b, c) {
}
}
The decorator uses JSON.stringify
on the method arguments to generate a cache key by default, which should work for
most scenarios, but can be inefficient or unusable in others. You can replace it by passing your own cache key
generator to the decorator function. It will be called with the class instance as an argument.
The function can return anything that's uniquely identifiable in a Map.
import {Memoise} from '@aloreljs/memoise-decorator';
class MyClass {
constructor() {
this.someId = 'foo';
}
@Memoise(function(label, data) {
return `${this.someId}:${label}:${data.id}`
})
someMethod(label, data) {
}
}
The cache generator function gets called with fn.apply(instance, methodArguments)
and therefore can access instance
data. The syntax is a bit different for Typescript and Babel.
Decorators get applied after your class is already established, therefore the syntax is simple
import {Memoise} from '@aloreljs/memoise-decorator';
class MyClass {
public readonly multiplier = 5;
@Memoise(MyClass.prototype.serialiser)
public method(num: number): string {
return `The number is ${num}`;
}
private serialiser(num: number): number {
return num * this.multiplier;
}
}
Decorators get applied as part of the class definition, therefore you need to wrap the cache key generator:
import {Memoise} from '@aloreljs/memoise-decorator';
class MyClass {
constructor() {
this.multiplier = 5;
}
@Memoise(function() { // Arrow functions will not work
return MyClass.prototype.serialiser.apply(this, arguments);
})
method(num) {
return `The number is ${num}`;
}
serialiser(num) {
return num * this.multiplier;
}
}
This might be useful for methods that don't accept parameters in the first place.
import {Memoise} from '@aloreljs/memoise-decorator';
class MyClass {
@Memoise.all()
method() {
return 'foo';
}
}
After being called at least once, the method will get a MEMOISE_CACHE
property containing the cache.
import {MEMOISE_CACHE, Memoise} from '@aloreljs/memoise-decorator';
class MyClass {
@Memoise()
method(a) {
return a + 10;
}
}
const instance = new MyClass();
console.log(instance.method[MEMOISE_CACHE]); // Undefined
instance.method(instance.method(1));
console.log(instance.method[MEMOISE_CACHE]); // Map([['[1]', 11]])