javascriptjquerygarbage-collectionjavascript-engine

Is there a performance cost to using the same query selector again and again?


Does the performance cost of searching for the same query selector within a document add up to a significant one, or does some code in the pipeline -- from the JavaScript library in use (e.g. jquery) or the JavaScript engine or the browser engine -- cache query selectors.

$(document).ready(function() {

  var foo = $("#foo");

  doThis();
  doThat();
  thenDoThat();
  ...

  function doThis() {
    $("#foo")...
    ...
  }

  function doThat() {
    $("#foo")...
    ...
  }

  function thenDoThat() {
    $("#foo")...
    ...
  }

  ...
});

I do understand the lifetime of objects esp. in a garbage collected environment. So, the reply that the scope of the object will determine its life-time will not quite satisfy my curiosity, as that fact is obvious.

My question really is, if I accessed $("#foo") over and over again,

  1. will that add up to a significant CPU time and so will caching it in my code at an appropriate level obviate such cost, or

  2. some code already caches it, or

  3. is it totally negligible no matter how many times done?


Solution

  • Yes, there's a performance impact. Every time $(selector) runs, a new jQuery object must be constructed. That said, the impact is pretty minor unless you run a huge number of those in a short period of time. For example:

    const t1 = performance.now();
    
    for (let i = 0; i < 300000; i++) {
      const html = $('div').html();
    }
    
    const t2 = performance.now();
    
    const div = $('div');
    for (let i = 0; i < 300000; i++) {
      const html = div.html();
    }
    
    const t3 = performance.now();
    
    console.log(t2 - t1);
    console.log(t3 - t2);
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div>foo</div>

    Constructing the jQuery object does take a non-zero amount of CPU time, but it's still not much. If you do have to worry about efficiency, you might just use standard Javascript instead, which will have additional improvement over jQuery methods (even over saving a reference to a jQuery object).

    const t1 = performance.now();
    for (let i = 0; i < 300000; i++) {
      const html = $('div').html();
    }
    const t2 = performance.now();
    
    const $div = $('div');
    for (let i = 0; i < 300000; i++) {
      const html = $div.html();
    }
    const t3 = performance.now();
    
    for (let i = 0; i < 300000; i++) {
      const html = document.querySelector('div').innerHTML;
    }
    const t4 = performance.now();
    
    const div = document.querySelector('div')
    for (let i = 0; i < 300000; i++) {
      const html = div.innerHTML;
    }
    const t5 = performance.now();
    
    console.log('jQuery re-selection', t2 - t1);
    console.log('jQuery saving reference', t3 - t2);
    console.log('vanilla re-selection', t4 - t3);
    console.log('vanilla saving reference', t5 - t4);
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div>foo</div>