diff --git a/index.js b/index.js index 42dc788..7c82c37 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ const mimicFn = require('mimic-fn'); const isPromise = require('p-is-promise'); +const fnStore = new WeakMap(); const cacheStore = new WeakMap(); const defaultCacheKey = function (x) { @@ -19,6 +20,14 @@ module.exports = (fn, opts) => { cachePromiseRejection: false }, opts); + const fnKey = JSON.stringify(opts); + if (fnStore.has(fn)) { + const optStore = fnStore.get(fn); + if (optStore[fnKey]) { + return optStore[fnKey]; + } + } + const memoized = function () { const cache = cacheStore.get(memoized); const key = opts.cacheKey.apply(null, arguments); @@ -55,6 +64,10 @@ module.exports = (fn, opts) => { mimicFn(memoized, fn); cacheStore.set(memoized, opts.cache); + if (!fnStore.has(fn)) { + fnStore.set(fn, {}); + } + fnStore.get(fn)[fnKey] = memoized; return memoized; }; diff --git a/test.js b/test.js index d4b06d6..f2cf3ca 100644 --- a/test.js +++ b/test.js @@ -17,6 +17,24 @@ test('memoize', t => { t.is(memoized('foo', 'bar'), 2); }); +test('memoize itself is memoized', t => { + let i = 0; + const f = () => i++; + let memoized = m(f); + t.is(memoized(), 0); + t.is(memoized(), 0); + memoized = m(f); + t.is(memoized(), 0); + t.is(memoized('foo'), 1); + t.is(memoized('foo'), 1); + memoized = m(f); + t.is(memoized('foo'), 1); + t.is(memoized('foo', 'bar'), 2); + t.is(memoized('foo', 'bar'), 2); + memoized = m(f); + t.is(memoized('foo', 'bar'), 2); +}); + test('memoize with multiple non-primitive arguments', t => { let i = 0; const memoized = m(() => i++); @@ -40,6 +58,25 @@ test('maxAge option', async t => { t.is(memoized(1), 1); }); +test('maxAge option deletes old items', async t => { + let i = 0; + const f = () => i++; + const cache = new Map(); + const deleted = []; + cache.delete = item => deleted.push(item); + const memoized = m(f, {maxAge: 100, cache}); + t.is(memoized(1), 0); + t.is(memoized(1), 0); + t.is(cache.has(1), true); + await delay(50); + t.is(memoized(1), 0); + t.is(deleted.length, 0); + await delay(200); + t.is(memoized(1), 1); + t.is(deleted.length, 1); + t.is(deleted[0], 1); +}); + test('cacheKey option', t => { let i = 0; const f = () => i++;