Skip to content

Commit

Permalink
feat: memoize calls to memoize itself.
Browse files Browse the repository at this point in the history
This way memoize can wrap functions across multiple files in a single
realm but still share a cache between those calls. Consider:

```js
// file A:
const foo = require('foo')
const memfoo = mem(foo)
``

```js
// file B:
const foo = require('foo')`
const memfoo = mem(foo)
```
  • Loading branch information
keithamus committed Feb 21, 2018
1 parent aedb787 commit def0148
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 0 deletions.
13 changes: 13 additions & 0 deletions index.js
Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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;
};
Expand Down
37 changes: 37 additions & 0 deletions test.js
Expand Up @@ -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++);
Expand All @@ -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++;
Expand Down

0 comments on commit def0148

Please sign in to comment.