Home > Programming > Easily cache results from Javascript functions

Easily cache results from Javascript functions

UPDATE: Adrian Quark has a much safer approach for the cache in his comment. I guess I should have tested mine better with other functions than the computational ones I was doing :)

A short Javascript function I made in a project to cache result from functions in Javascript. You can use this function where it makes sense to cache.

The cache method

cacheMethod.cache = {};

function cacheMethod(context, fn) {
	var funcName = fn.toString();
	funcName = funcName.substr('function '.length);
	funcName = funcName.substr(0, funcName.indexOf('('));

	context[funcName] = function() {

		if (cacheMethod.cache[funcName] == null)
			cacheMethod.cache[funcName] = {};

		// Create a unique key of parameters
		var key = Array.slice.call(arguments).join('|');
		if (cacheMethod.cache[funcName][key] == null)
			cacheMethod.cache[funcName][key] = fn.apply(this, arguments);

		return cacheMethod.cache[funcName][key];
	};
}

Usage
If we have a function like isPrime borrowed from John Resig:

function isPrime( num ) {

  var prime = num != 1; // Everything but 1 can be prime
  for ( var i = 2; i < num; i++ ) {
    if ( num % i == 0 ) {
      prime = false;
      break;
    }
  }

  return prime;
}

we can make the isPrime function cache-able with a single line of:

cacheMethod(this, isPrime);

No when we try to call the isPrime 100 times with a large prime number, this first round is calculated and all subsequent rounds use the cache. You can see the difference by removing the cacheMethod line.

for (var i=0; i<100; i++)
		document.write(isPrime(58750291)+'<br/>');

Full example here: cache.html.

Categories: Programming Tags:
  1. Adrian Quark
    September 21st, 2009 at 15:45 | #1

    A few problems with this:
    1. the .name property is a much easier way to get the name of a function.
    2. this won’t work with anonymous functions.
    3. because it uses a global cache the cached values won’t be garbage collected even if the function goes away (e.g. it’s an event handler).
    4. if your function takes a variable number of arguments and one contains a “|” the cache won’t work correctly.
    5. if the function returns null this won’t be cached
    6. the cache key won’t work with Object values since they don’t have a unique string representation. You need to use something like http://www.timdown.co.uk/jshashtable/ to get around that.

    You can fix 1-5 with some minor modifications:

    function memoise(f) {
      var cache = {};
      return function () {
        var key = arguments.length+"|"+arguments.join("|");
        if (cache[key] === undefined) {
          cache[key] = f.apply(this, arguments);
        }
        return cache[key];
      }
    }
    
    isPrime = memoise(isPrime);
    
  2. Adrian Quark
    September 21st, 2009 at 15:46 | #2

    Sorry about the formatting, the blog software seems to lose indentation even though I used a <code/> block.

    [EDIT: Fixed :) Gunnar Steinn]

  3. Bob
    September 21st, 2009 at 16:44 | #3

    I came up with an alternative version as well, looks like Adrian beat me to it.

    My commentary is here:

    http://www.reddit.com/r/programming/comments/9mm5o/easily_cache_results_from_javascript_functions/c0deuu8

    I put Adrian’s thing in there, to get the formatting back. Woo!

  4. September 21st, 2009 at 17:03 | #4

    Adrians approach works well except that arguments isn’t a proper Array in Javascript so you will have to use the “Array.slice.call(arguments).join(’|')” line from my code.

  5. jetm
  6. September 23rd, 2009 at 22:48 | #6

    @jetm
    Thanks, fixed the link