medikoo / memoizee

Complete memoize/cache solution for JavaScript
ISC License
1.73k stars 61 forks source link

Different cache id resolution per argument #99

Closed amaury1093 closed 5 years ago

amaury1093 commented 5 years ago

My function has signature:

function myFunction(a: object, b: object): void;

const memoized = memoize(f);

If I understood well, when I memoize that, it memoizes by object reference:

memoize({ foo: 'bar' }, { bar: 'qux' });
memoize({ foo: 'bar' }, { bar: 'qux' }); // Cache NOT hit

I wish to memoize the 1st argument by its serialized version, and the 2nd argument by object reference. Namely, if:

const first = { foo: 'bar' };
const second = { bar: 'qux' };

The I want the 3 following tests to pass:

Test 1:

memoize(first, second);
memoize({ foo: 'bar' }, second); // Cache hit
memoize(first, second); // Cache hit

Test 2:

memoize(first, second);
memoize(first, { bar: 'qux' }); // Cache not hit
memoize({ foo: 'bar' }, { bar: 'qux' }); // Cache not hit

Test 3:

memoize({ foo: 'bar' }, second);
memoize({ foo: 'bar' }, second); // Cache hit
memoize(first, second); // Cache hit

Is that possible with the current version?

medikoo commented 5 years ago

Is that possible with the current version?

Yes it is, but you need to provide your own normalizer, which can work as e.g.:

const idCounter = 0;
const idMap = new WeakMap();
const getObjectId = obj => {
  if (idMap.has(obj)) return iMap.get(obj);
  const id = ++idCounter;
  idMap.set(obj, id);
  return id;
};

const memoized = memoize(f, {
  normalizer: ([a, b]) => `${getObjectId(b)},${JSON.stringify(a)}`
});
medikoo commented 5 years ago

Alternatively, if it would be the case where first argument is expected to be mapped by reference and second by serialized representation, it can be done more straightforward with weak mode:

const memoizeWeak = require("memoizee/weak");

const memoized = memoizeWeak(f, { normalizer: ([,b]) => JSON.stringify(b) });