jQuery DOM cache object
The first problem with jQuery is uncached queries.
Instead of doing something like:
$('h1').addClass('inactive');
$('h1').text('hello');
$('h1').animate({height: "100px"});
You have to do that:
var $h1 = $('h1');
$h1.addClass('inactive');
$h1.text('hello');
$h1.animate({height: "100px"});
Because the h1
is just fetched once in the DOM. This is faster.
Sometimes you will reuse this same h1
in another function. So you have to re-declare the $h1
variable, and it's not optimised.
Instead, you can do a global approach for caching DOM object from jQuery: Create a global object with the selector as key and DOM object as value. This is an implementation:
DOMCACHESTORE = {};
DOMCACHE = {
get: function(selector, force) {
if (DOMCACHESTORE[selector] !== undefined && force === undefined) {
return DOMCACHESTORE[selector];
}
DOMCACHESTORE[selector] = $(selector);
return DOMCACHESTORE[selector];
}
};
How to use it?
DOMCACHE.get('h2').addClass('super');
// Later:
DOMCACHE.get('h2').removeClass('super');
This DOMCACHE.get('h2')
will be the same, and it will just be fetched once.
If you have new h2
on the page, added by JavaScript, you can force the re-fetch:
DOMCACHE.get('h2', true).addClass('super');
// Now, we have all h2:
DOMCACHE.get('h2').addClass('all');
It's a very simple trick for better performance on your jQuery code.
Any suggestions or bugs? Let me know.
Written by Damian Le Nouaille
Related protips
14 Responses
I think two global objects is not the best javascript practice
You can of course encapsulate everything in a plugin or better implementation. That's why I wrote "This is an implementation".
Nice idea! I also wanted to combat this same issue and wrote my own protip on the subject: https://coderwall.com/p/qrbasw
Any reason you checked force === undefined
? In this case won't false and true both force the refresh?
If you don't specify something (normal case) it won't force refresh. If you set something (true
or other) it will force. You can check force === true
if you want to be more specific.
You can also just chain your jQuery calls:
$('h1').addClass('inactive')
.text('hello')
.animate({height: "100px"})
How about something like:
$C = (function($){
var DOMCACHESTORE = {};
return function(selector, force) {
if (DOMCACHESTORE[selector] !== undefined && !force) {
return DOMCACHESTORE[selector];
}
DOMCACHESTORE[selector] = $(selector);
return DOMCACHESTORE[selector];
}
})($);
Then you can replace all your "$('h1')" with "$C('h1')", which is a lot less to type than "DOMCACHE.get('h2')".
I think this reads better
$C = (function($) {
var DOMCACHESTORE = {};
return function(selector, force) {
if (DOMCACHESTORE[selector] === undefined || force)
DOMCACHESTORE[selector] = $(selector);
return DOMCACHESTORE[selector];
}
})($);
I added this to my CodePen, really usefull stuff, http://codepen.io/deiga/details/gdoKh
I made a JSPerf about this topic: http://jsperf.com/jquery-cached-domcache
I dunno, I stick to obj-pattern =\ just feels cleaner and easier to interpret down the road. pastie.org/8422291
@damln did I miss something, or is this in a different context?
Used in semantic module pattern
http://semantic-ui.com/spec/docs/module.commented.html
You may as well just declare a global object rather than a generic cache -- you should get the benefit of Intellisense from many IDE's, which you won't from magic strings.
Also, $ME = { h1: $('h1'), somethingelse: $('whatever') }
and $ME.yetanother = $('etc')
is much less complicated.