Performance in Javascript: Caching

Typically caching is something done on a web server to reduce expensive calls to databases or filesystems. It will keep commonly used resources in memory, allowing them to be accessed quickly. You can apply similar ideas to Javsascript.

When used in programs, this idea is called memoization. Essentially what you are doing is trading computational complexity for memory; that is, if something is hard to compute, you only do it once and save the result in memory. This is not always a good option, however, because memory is always finite. Here are two examples of when to use it:

jQuery Selectors – jQuery offers amazingly powerful selectors that let you pull precisely the node you want out of the DOM using CSS-like notation. For example

A complex selector
1
$("#wrapper ul#nav > li.first")

lets you select all list-items with a class of ‘first’, whom are children of a ul with an id ‘nav’, which is itself contained inside a div of id ‘wrapper’. Phew!

This is super handy, but few realize the complexity that jQuery is wrapping up for them: with only a few shortcuts from native DOM methods (getElementById, notably) it is basically traversing the entire DOM and applying various rules to each node it encounters. On a page of any size, this computational effort adds up quickly and show up as a laggy UI.

A way to cache this function is to write code that avoids making that jQuery selection every time the collection of nodes is required:

Value memoization
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Bad!
for (var i = 0; i < $('#myPage a').length; i++ {
    //do something with each anchor element
    //this traverses the DOM each loop
}

//Good!
var elements = $('#myPage a');
var len = elements.length;

for (var j = 0; j < len; j++) {
    //do something with each anchor
    //this only compares two integers each loop that you've saved off
}

AJAX call caching – AJAX is sweet. Using a an XHR object to call a server for data is now the bread and butter of the web. Each call though has a transaction cost associated with it: XHR overhead, network latency, remote server CPU time… Yuck. Let’s see how to cache a buffer call:

Ajax Memoization
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//a function that makes an AJAX call to a remote source
//NOTE: This isn't practical for rapidly changing data

myObject.prototype.callTwitterAPI = function() {
    var self = this; //to preserve context
    var Data;
    $.get('twitter.com/RESTfulAPI.html?query...', function(data) {
        Data = data;
    });

    this.callTwitterAPI = function() {
        return Data;  //this is the key. This overwrites the current function with one skipping the AJAX call
    }

    return Data; //Finally return the data
}

So this is a function that when first called with make an AJAX request, but then it redefines itself to simply return the already retrieved data for future calls. Powerful stuff that can start to make your client side code fly.