Selector Caching in jQuery

One of the first critiques I find myself writing while I review JavaScript code is "cache your selectors."

One of the first critiques I find myself writing while I review JavaScript code is “cache your selectors.”

Like me, many JavaScript developers are self taught and worked their way through a basic understanding of scripting through tutorials. Unfortunately, many tutorials sacrifice cleanliness for brevity, leading to functional snippets of code that look absolutely horrible in larger collections of code.

The worst offender is the way developers handle jQuery selectors.  Most commonly, I see things like [cci]$( this )[/cci] repeated several times within a callback function. Or [cci]$( ‘#selector’ )[/cci] used throughout a script to both bind and unbind multiple events.

What new developers don’t realize is that every call to [cci]$( something }[/cci] asks jQuery to rescan for the matching element, wrap it in a jQuery object, and create a new instance of something you already have in memory. If your code crashes due to memory cascades, overuse of redundant selectors might be related.

Actually, if you use a more advanced IDE like PhpStorm or WebStorm, the IDE itself will alert you to this issue so you can correct it.

Caching Selectors

In a small application, caching selectors isn’t that difficult. Just declare all of your objects at the top of your closure and use the new variables throughout your script.

var $window = $( window ),
$document = $( document ),
$footer = $( '#footer' ),
$sidebar = $( '#sidebar' ),
$images = $( 'img' );

Unfortunately, as the length of your application grows, the size of this selector cache grows and becomes difficult to manage. I’ve been experimenting with different forms of in-memory caching for JavaScript applications, and came up with a simple selector cache object that makes it easier to wrangle your references.

function Selector_Cache() {
var collection = {};

function get_from_cache( selector ) {
if ( undefined === collection[ selector ] ) {
collection[ selector ] = $( selector );
}

return collection[ selector ];
}

return { get: get_from_cache };
}

var selectors = new Selector_Cache();

// Usage $( '#element' ) becomes
selectors.get( '#element' );

Using [cci]selectors.get( something )[/cci] in your code from that point forward might be slightly more characters than the redundant selectors we’ve used previously, but it’s far more performant. Once you run code through a minifier, the character count difference will be negligible anyway.