Recently I've watched a presentation by Kevin Millikin about Google Chrome's JavaScript engine.
I was really impressed by the clever ways they found to improve speed. One of the technique used was polymorphic inline caching (the name is more complicated than the technique itself..), a technique I knew for a while, but never found much real life situations which justified its utilization.. until today ago.
When taking off the polymorphic aspect, the implementation becomes really simple and is perfect for a primitive caching mechanism. I used something similar for the $.tpl plugin.
So here's how I implemented it;
$.extend({ic: function(){ // [key, value, scope]
var scope = arguments[2] || this;
scope._ic = scope._ic || {};
if (arguments.length == 1) {
return this._ic[arguments[0]] || false;
}
else if (!arguments[1].jquery) {
return scope._ic[arguments[0]] = arguments[1];
}
return scope._ic[arguments[0]] = arguments[1];
}});
_$ = function(sel, scope) {
var c = $.ic(sel);
return c && c || $.ic(sel, $(sel));
};
The code can be used as follow;
// Store and get publicly
$.ic('test', $(selector));
$.ic('test');
// Store and get privately
$.ic('test', $(selector), this);
$.ic('test');
The _$ function allow caching at selector level, which means you can use it normally like the $ except that the selector engine will process every selection only once.
Obviously this is not the kind of behavior we want when HTML nodes are being inserted or deleted dynamically, but in a handful of other situations this might be useful.
Here's a simple function to profile it:
function testIC(s) {
var selector = s || 'a';
console.profile('Inline caching (global)');
$.ic('test', $(selector));
for (x=0;x < 100;x++) {
$.ic('test');
}
console.profileEnd('Inline caching (global)');
console.profile('Inline caching (scoped)');
$.ic('test', $(selector), this);
for (x=0;x < 100;x++) {
$.ic('test');
}
console.profileEnd('Inline caching (scoped)');
console.profile('No caching');
for (x=0;x < 100;x++) {
$(selector); // get global
}
console.profileEnd('No caching');
}
Of course, basically this technique is almost equate to store the jQuery result object in a variable. However it offers the advantage that you can chose the scope of the variable, make it public or private, without polluting the global object.
And well, I also think that it's syntactically neat.
cheers
jQuery used to have a cache, I cannot find it in the recent sources though.
vs
shorter and clearer and it has not advantages since you don't listen to DOM modification events (https://developer.mozilla.org/En/DOM_Events) to automatically invalidate your cache.
For the cache itself, I'd keep it inside jQuery; jQuery.cache = {}
What's the real benefits? The syntax isn't even better than doing it manually.
The benefit is mostly that you can reuse $.ic('test'); anywhere in your code without resorting to a global variable.
Another use case would be for frequent selection of the same DOM elements that are not supposed to be modified.
I'm aware that this technique has a limited utility scope, that's why it probably won't make it to my jquery.utils library. It was mostly an exercise I wanted to do to see if this would be a viable technique and well, for fun.
PS: About the jQuery.cache idea, initially I used the window object. I'm not sure why, but noticed it took slightly longer to store and fetch in a external scope than when using this.