4

I know jQuery doesn’t cache collections of element, f.ex calling:

$('.myclass').html('hello');
$('.myclass').html('bye');

Will make jQuery climb the DOM twice.

But how about cached DOM nodes?

var elems = document.querySelectorAll('.myclass');

$(elems).html('hello');
$(elems).html('bye');

Will jQuery cache those internally, or will they be equally slow as the first example?

To clarify: will jQuery keep a reference to elems and cache $(elems) internally so it won’t have to apply the same $() wrapper every time?

Something like:

cache = {}
constructor = function(collection)
    if collection in cache
        return cache[collection]
    else construct(collection)
David Hellsing
  • 106,495
  • 44
  • 176
  • 212
  • `document.querySelectorAll('.myclass');` returns an immediately evaluated collection. It is *this* which prevents "climbing the DOM twice", nothing to do with jQuery. `$(..)` will happily take a collection of DOM nodes (in the first example it took a selector). –  Sep 05 '12 at 08:07
  • @pst Yes I know it can take a collection, but will it cache the wrapper for the very same collection? – David Hellsing Sep 05 '12 at 08:09
  • 1
    @David - No, it won't. That's what I and pst have both said in our answers. jQuery won't do anything with the matched set beyond the statement to which that matched set applies. It's up to *you* to keep a reference to a jQuery object if you're going to be using it multiple times. – James Allardice Sep 05 '12 at 08:14

2 Answers2

12

Assuming I've understood your question correctly, then no, jQuery won't keep a reference to the selected nodes beyond the statement that uses them:

$('.myclass').html('hello'); //Select all .myclass elements, then change their HTML
$('.myclass').html('bye'); //Select all .myclass elements, then change their HTML again

If you maintain a reference to those selected nodes separately, it will be faster:

var elems = document.querySelectorAll('.myclass'); //Select all .myclass elements
$(elems).html('hello'); //Change their HTML (no need to select them)
$(elems).html('bye'); //Change their HTML (no need to select them)

The difference won't be massive (unless your DOM is very complicated) but there will be a difference:

enter image description here


Update

will jQuery keep a reference to elems and cache $(elems) internally so it won’t have to apply the same $() wrapper every time?

No, it won't. As stated above, the reference to the matched set of elements will not be maintained beyond the statement to which it applies. You can improve the performance of your code by keeping a reference to jQuery objects that are used throughout, rather than selecting them again each time, or even wrapping a stored set of native DOM nodes in a jQuery object each time.

James Allardice
  • 164,175
  • 21
  • 332
  • 312
  • So you’re saying that `$(elems)` is not cached internally, wich means the jQuery layer will be applied again even if the nodes are exactly the same? – David Hellsing Sep 05 '12 at 08:02
  • Yes, that's correct. It would be more efficient still to maintain a reference to the jQuery object yourself e.g. `var elems = $(".myclass")` (which is what I've done in the jsperf.com test linked to in my answer). – James Allardice Sep 05 '12 at 08:03
  • Yes, I did a test too: http://jsperf.com/domcache and the difference seems extremely small between the later two, so I imagined jQuery did some internal cache for the wrapper. – David Hellsing Sep 05 '12 at 08:06
  • @David jQuery only "wraps" DOM nodes. If a collection of DOM nodes are passed into it .. there is no "selecting" that occurs. –  Sep 05 '12 at 08:08
  • @pst yes, but jQuery will still attach prototypes even if a raw collection is passed. My question was basically if this procedure was cached internally between equal collections of elements. – David Hellsing Sep 05 '12 at 08:11
  • You can even cache the jquery object instead: `var elems = $(document.querySelectorAll('.myclass')); //Select all .myclass elements and return jQuery object elems.html('hello'); //Change their HTML (no need to call $ again) elems.html('bye'); //Change their HTML (no need to call $ again) ` – el producer Sep 05 '16 at 06:33
  • 5% slower is very huge. The difference might be bigger on slower computers – Peter Chaula Dec 11 '17 at 19:14
0

If "cache" means "keep the DOM elements in the internal collection for that jQuery object" .. then yes.

Imagine

jq = $(elementListOrSelector)

where jq[0..jq.length-1] evaluate to the respectively DOM element. For instance, jq[0] evaluates to the first DOM element represented by the jQuery object, if any. Note that this collection is not magically changed once it has been built (and the way in which it was built does not matter).

However there is no "cache" outside of simply keeping the immediate results for that particular jQuery object.