Last Updated: September 09, 2019
·
8.257K
· damln

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.

14 Responses
Add your response

I think two global objects is not the best javascript practice

over 1 year ago ·

You can of course encapsulate everything in a plugin or better implementation. That's why I wrote "This is an implementation".

over 1 year ago ·

Nice idea! I also wanted to combat this same issue and wrote my own protip on the subject: https://coderwall.com/p/qrbasw

over 1 year ago ·

Any reason you checked force === undefined? In this case won't false and true both force the refresh?

over 1 year ago ·

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.

over 1 year ago ·

You can also just chain your jQuery calls:

$('h1').addClass('inactive')
.text('hello')
.animate({height: "100px"})
over 1 year ago ·

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')".

over 1 year ago ·

I think this reads better

$C = (function($) {
  var DOMCACHESTORE = {};

  return function(selector, force) {
    if (DOMCACHESTORE[selector] === undefined || force)
      DOMCACHESTORE[selector] = $(selector);
    return DOMCACHESTORE[selector];
  }
})($);
over 1 year ago ·

@pgib : You can but sometimes you use the same selector in multiple functions. Not necessarily chaining.

@leemour : Nice one!

over 1 year ago ·

I added this to my CodePen, really usefull stuff, http://codepen.io/deiga/details/gdoKh

over 1 year ago ·

I made a JSPerf about this topic: http://jsperf.com/jquery-cached-domcache

over 1 year ago ·

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?

over 1 year ago ·
over 1 year ago ·

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.

over 1 year ago ·