using memoize function with underscore.js

All we need is an easy explanation of the problem, so here it is.

I am trying to cache the result from an ajax call using memoize function from Underscore.js. I am not sure of my implementation. Also how to retrieve back the cached result data using the key. Below is my implementation:

Javascript code:

var cdata = $http
.get(HOST_URL + "/v1/report/states")
.success(function(data) {
    //put the result in the angularJs scope object. 
    $scope.states = data;
});

//store the result in the cache.
var cachedResult = _.memoize(
    function() {
        return cdata;
    }, "states");

Is my usage of memoize to store the result of ajax is correct. Also once it is put in cache, how to retrieve based on the key. i.e ‘states’.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Let us understand how _.memoize works, it takes a function which needs to be memoized as first argument and caches the result of the function return for given parameter. Next time if the memoized function is invoked with same argument it will use cached result and the execution time for the function can be avoided. So it is very important to reduce the computation time.

As mentioned, the above fibonaci function it memoized works perfectly fine as the argument has a primitive type.

The problem occurs when you have to memoize a function which accepts an object. To solve this, _.memoize accepts an optional argument hashFunction which will be used to hash the input. This way you can uniquely identify your objects with your own hash functions.

The default implementation of _.memoize (using the default hash function) returns the first argument as it is – in the case of JavaScript it will return [Object object].

So for e.g.

var fn = function (obj){ some computation here..}
var memoizedFn = _.memoize(fn);

memoizedFn({"id":"1"}) // we will get result, and result is cahced now

memoizedFn({"id":"2"}) // we will get cached result which is wrong

why default has function in _.memoize is function(x) {return x}

the problem can be avoided by passing a hash function

_.memoize(fn, function(input){return JSON.stringify(input)});

This was a real help for me when I was using _.memoize for a function that was working on arrays arguments.

Hope this helps many people in their work.

Method 2

_.memoize takes a function:

var fibonacci = _.memoize(function(n) {
  return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
});

You should understand that this is just an extra wrapper function that makes function that you pass it as an argument smarter( Adds extra mapping object to it ).

In example above function that computes fibonacci number is wrapped around with _.memoize. So on every function call (fibonacci(5) or fibonacci(55555)) passed argument matched to return value so if you need to call one more time fibonacci(55555) it doesn’t need to compute it again. It just fetches that value from that mapping object that _.memoize provided internally.

Method 3

If you are using Angular.js’s $http, you probably just want to pass {cache : true} as a second parameter to the get method.

To store values using key value pairs, you may want to use $cacheFactory, as described in other answers like here. Basically:

var cache = $cacheFactory('cacheId');
cache.put('states', 'value');
cache.get('states');

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply