Search code examples
javascriptmemoization

Memoize callback function


I was trying this memoization on

function getData(n, m, callback){
    callback(n+m);
};
let memoizedData = memoize(getData);
console.log(memoizedData(5, 4, (result)=>{})) // 9;

I want to cache the result i,e, 9 so whenever next call happens it takes from cache. I understand memoization if getData would have return n+m instead of putting to the callback. Any help will be appreciated.

Edits: Want to implement this via vanillaJs. Edited the above question for more clarity

function getData(n, m, callback){
    callback(n+m);
};
let memoizedData = memoize(getData);
memoizedData(5, 4, (result)=>{console.log(result)}) // 9;
memoizedData(5, 4, (result)=>{console.log(result)}) // 9 - returned from cache

Solution

  • If I understand correctly, you are asking for an implementation of memoize. As to your console.log: this is strange, since the result is not returned, but passed as an argument to a callback. So you should actually print within that callback. You could even pass console.log as callback.

    For the implementation of memoize, I will assume that the function to memoize will always have a callback as last parameter.

    First, memoize should return a function which accept the same arguments as the function that is memoized.

    The idea is to maintain a Map, keyed by the arguments that are passed to the function (excluding the callback argument), and with the corresponding result. One way to build the key is to form the JSON representation of the arguments.

    When memoize is called, and the arguments form a key that is already present in the map, then call the callback with the corresponding value from the map. If not present, then call the function with the same set of arguments, except for the callback. Let the callback be a function that stores the result in the map, and then passes the result on to the callback that was passed to memoize.

    Here is how you could write it:

    function memoize(func) {
        let map = new Map; // for memoization
        return function(...args) {
            let callback = args.pop(); // last argument must be a function
            let key = JSON.stringify(args);
            let result = map.get(key);
            if (result !== undefined) {
                console.log(`getting result from map.get('${key}')`);
                return callback(result);
            }
            console.log(`calling ${func.name}(${args.join(", ")}, callback)`);
            func(...args, result => {
                console.log(`writing result with map.set('${key}', ${result})`);
                map.set(key, result);
                callback(result);
            });
        }
    }
    
    function getData(n, m, callback){
        callback(n+m);
    }
    let memoizedData = memoize(getData);
    
    
    memoizedData(5, 4, console.log) // 9 calling getData;
    memoizedData(5, 4, console.log) // 9 from memory;

    Note that this:

    memoizedData(5, 4, console.log)
    

    ...is just "short" for:

    memoizedData(5, 4, (result) => console.log(result))
    

    The only difference is that there is an extra wrapper function around console.log, but practically there is no real difference.