I'm struggling to solve a question on big front end, link. The task is to implement a general memoization function. I came across this solution, but I'm having trouble understanding what the resolver is/does. First time I've come across that term and searching google was unhelpful.
function memo(func, resolver = (...args) => args.join('_')) {
const cache = new Map();
return function(...args) {
const cacheKey = resolver(...args);
if (cache.has(cacheKey)) {
return cache.get(cacheKey);
}
const value = func.apply(this, args);
cache.set(cacheKey, value);
return value;
}
}
It's not a "resolver" but more like an "arguments hasher" -- a function that returns a unique hash given a set of arguments.
The idea here is to cache the result of calling the memoized function with a given set of arguments by storing the result in a map using the "arguments hash" as the key.
(It's probably called a "resolver" because it lets the memoizer resolve cache entries.)
(The default "resolver" in your code snippet naively concatenates argument values with the "_" delimiter. It's naive because it doesn't account for cases where an argument itself may contain a "_".)
Assuming you have a function that takes some number of arguments...
var underlyingFunction = function(arg1, arg2, arg3){
return arg1+arg2+arg3;
};
You want to create a version of this function that caches the return values for specific values passed in, so that it can skip the calculations and just return the same value as was returned last time those same args were passed in.
And really... rather than code this one function to do that specifically, you want to create a function that can create such a caching function from any underlying function...
To do this, you need a function that:
Re-writing your sample code to more fully explain it
const underlyingFunction = function(arg1, arg2, arg3) {
return arg1 + arg2 + arg3;
};
const serializingFunction = function(...args) {
/*
creates a '_' delimited string to use as unique id
for that particular function call
*/
return args.join('_');
};
var cachingFunctionCreator = function(func, serializer) {
// if serializer wasnt passed in, have it be serializingFunction
serializer = serializer || serializingFunction;
// to store all function call ids and their result values
const cache = new Map();
// return the new function
return function(...args) {
// call serializing function to get the function call id
const cacheKey = serializer(...args);
// check to see if we've seen this id before
// if so, dont call the underlying function...
// just return the previously stored result for that id
if (cache.has(cacheKey)) {
console.log(cacheKey + ' was passed in previously');
return cache.get(cacheKey);
}
// otherwise, call the underlying function with the current args
// store the id and result value into the map
// and return the current result
console.log('first time seeing: ' + cacheKey);
const value = func.apply(this, args);
cache.set(cacheKey, value);
return value;
};
};
var cachingFunction = cachingFunctionCreator(underlyingFunction);
console.log('Calling underlying function');
console.log(underlyingFunction('a', 'b', 'c'));
console.log('Calling cached function');
console.log(cachingFunction('a', 'b', 'c'));
console.log('Calling cached function');
console.log(cachingFunction('d', 'e', 'f'));
console.log('Calling cached function');
console.log(cachingFunction('g', 'h', 'i'));
console.log('Calling cached function');
console.log(cachingFunction('a', 'b', 'c'));