-
-
Save jtsternberg/14978579a9edf42ed069 to your computer and use it in GitHub Desktop.
function Selector_Cache() { | |
var elementCache = {}; | |
var get_from_cache = function( selector, $ctxt, reset ) { | |
if ( 'boolean' === typeof $ctxt ) { | |
reset = $ctxt; | |
$ctxt = false; | |
} | |
var cacheKey = $ctxt ? $ctxt.selector + ' ' + selector : selector; | |
if ( undefined === elementCache[ cacheKey ] || reset ) { | |
elementCache[ cacheKey ] = $ctxt ? $ctxt.find( selector ) : jQuery( selector ); | |
} | |
return elementCache[ cacheKey ]; | |
}; | |
get_from_cache.elementCache = elementCache; | |
return get_from_cache; | |
} | |
var cache = new Selector_Cache(); | |
// get selector | |
cache( '#selector' ); | |
// get selector and reset cache | |
cache( '#selector', true ); | |
// get selector with $context | |
cache( 'img', cache( '#selector' ) ); | |
// get selector with $context, and reset | |
cache( 'img', cache( '#selector' ), true ); | |
// get selector with $context, and reset both selector and $context (whoa) | |
cache( 'img', cache( '#selector', true ), true ); | |
// Manually add a selector | |
cache.elementCache['#another-id'] = jQuery( document.getElementById( 'another-id' ) ); | |
// Then use it: | |
cache( '#another-id' ); |
Good call! updated!
I think the collectionID
variable can be moved inside get_from_cache()
to make it local to that function call.
@salcode it could, but I don't see the purpose in it. I am not too worried about polluting scope within Selector_Cache.
Threading and concurrency in JS are out of my depth so perhaps this isn't even possible but if the same instance were called at the same time wouldn't the collectionID
value be shared between them?
No, the value of collectionID
will be explicitly set with every call, thanks to line 10. I/you could declare the var there.
Hi Justin, here's what I meant on Twitter about the context selector needing to be unique to prevent collisions. Say you have the following HTML:
<div class="record">
<ol>
<li>Track 1</li>
<li>Track 2</li>
<li>Track 3</li>
</ol>
</div>
<div class="record">
<ol>
<li>Track A</li>
<li>Track B</li>
<li>Track C</li>
</ol>
</div>
jQuery allows for a DOM Element, document, or jQuery to use as context. So if I needed to perform an action on each record, I could do something like this:
$( '.record' ).each(function( index, el ) {
// Various methods to cache tracks using a record as context.
$tracks = $( 'li', this );
$tracks = $( 'li', el );
$tracks = $( 'li', $( el ) );
//...
// More code using the $tracks collection.
});
With that in mind, this
, el
, or $( el )
can't be used as context with the selector cache, otherwise it creates collisions in the collections
object. So my question was, does this approach assume that context must be a unique string, such as an id
or other fully qualified selector?
@bradyvercher Ah, I thought you might mean something like that. Honestly, I'm not sure, and I'd love to test it. I think trying to use cached variables in a setting like that may be overkill/unnecessary anyway, but still worth looking into ($( '.record' )
should be cached, but the li
selector inside the loop probably doesn't need to be as it's unlikely you'd need to refer to it again).
Hi jtsternberg,
Can you please tell me how to use the cache selector after caching it in this case?
Thanks,
Lakin
@lakinmohapatra everything after var cache = new Selector_Cache();
are example for how to use it. cache( '#selector' );
There is something wrong because calling to cache( '#selector', true );
it fails with: Uncaught TypeError: $ctxt.find is not a function(…)
I think you can fix it setting $ctxt = false
when $ctxt is typeof boolean in line 6.
First off, @jsternberg this is a very nice snippet. I would love to adopt this into my code, however... I'm having issues with resetting the cached selectors.
Here's my situation...
I have 3 JS files:
- File 1: Sets up the variables (caching all the repetitive selectors).
- File 2: Manipulates the HTML on the page, using the cached selectors from
File 1
. - File 3: Manipulates the manipulated HTML from
File 2
.
Basically each file relies on the file loaded before the current file is loaded.
By the time it gets to File 3
, I can't just use the cached selector variable from File 1
, I need to reset SOME of the cached selector variables from File 1
. inside of File 3
, because File 2
has made changes to them.
Specifying: cache( '#selector', true );
in File 3
doesn't appear to be working. I don't get any errors in the console. Just blank. So I'm not sure what's wrong with it, but it doesn't appear to be working as expected.
Just to clarify, the variable still works with what was cached in File 1
, BUT it hasn't been updated from the changes made in File 2
, when specifying cache( '#selector', true );
in File 3
.
I'm just using jQuery('#selector');
to target the modified selector for the time being.
It would be nice to be able to reset the cached selector.
I have the same problem as @bradyvercher. If context is a simple jQuery selector like $( '#container' )
then it's good. But if it's complicated like $( '#container' ).next()
then the code that retrieves context's key won't work reliably.
While I can't imagine someone passing false as a value for the reset cache, unless I'm mistaken if one were to I think the cache would still be reset. e.g.
cache( '#selector', false );
I think if you change line 7 to
reset = context;
, it would account for this edge case.