@naturalcycles/js-lib
Version:
Standard library for universal (browser + Node.js) javascript
56 lines (54 loc) • 2.29 kB
JavaScript
// Based on:
// https://github.com/mgechev/memo-decorator/blob/master/index.ts
// http://decodize.com/blog/2012/08/27/javascript-memoization-caching-results-for-better-performance/
// http://inlehmansterms.net/2015/03/01/javascript-memoization/
// https://community.risingstack.com/the-worlds-fastest-javascript-memoization-library/
import { _getTargetMethodSignature } from './decorator.util.js';
import { jsonMemoSerializer, MapMemoCache } from './memo.util.js';
// memoSimple decorator is NOT exported. Only used in benchmarks currently
/**
* Memoizes the method of the class, so it caches the output and returns the cached version if the "key"
* of the cache is the same. Key, by defaul, is calculated as `JSON.stringify(...args)`.
* Cache is stored indefinitely in internal Map.
* There is more advanced version of memo decorator called `memoCache`.
*
* Supports dropping it's cache by calling .dropCache() method of decorated function (useful in unit testing).
*/
export const memoSimple = (opt = {}) => (target, key, descriptor) => {
if (typeof descriptor.value !== 'function') {
throw new TypeError('Memoization can be applied only to methods');
}
const originalFn = descriptor.value;
// console.log(`${key} len: ${originalFn.length}`)
// todo: optimization disabled until "default arg value" use case is solved (see memo.decorator.test.ts)
/*
let cache: MemoCache
// Function with 0 arguments
if (!originalFn.length) {
cache = new SingleValueMemoCache()
} else {
// Function with > 0 arguments
cache = new MapMemoCache()
// cache = new ObjectMemoCache()
}
*/
const cache = new MapMemoCache();
const { logger = console } = opt;
const keyStr = String(key);
const methodSignature = _getTargetMethodSignature(target, keyStr);
descriptor.value = function (...args) {
const ctx = this;
const cacheKey = jsonMemoSerializer(args);
if (cache.has(cacheKey)) {
return cache.get(cacheKey);
}
const res = originalFn.apply(ctx, args);
cache.set(cacheKey, res);
return res;
};
descriptor.value.dropCache = () => {
logger.log(`${methodSignature} @memo.dropCache()`);
cache.clear();
};
return descriptor;
};