简体   繁体   中英

Best way to optimize jQuery selector and why?

I am using this jQuery selector multiple times in my JSP:

 $("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']")

The solution I found on some blogs is that I should do first:

var customer=$('#customers')

And then use the above customer object for further calls.

 customer.find("tbody tr td input[type='checkbox'][name='selectedCustomers']")

My question is, does this solution will make any difference and why?

My understanding

When I do

$("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']")

jQuery internally will first get the object associated with div id="customers" (by document.getElementById("customers")) and then will traverse to the specified checkbox . And if I go by the suggested solution then document.getElementById("customers") will be fired only once and the rest will be the same. So I am saving myself from unnecessary multiple document.getElementById but the rest will be the same. Is my understanding correct? If yes is, just for the sake of my knowledge, is document.getElementById a more costly operation?

EDIT:-

i am not using only above said selector multiple times but also other possible selector under div id="customer". So question again is whats is difference in terms of performance if I cache the customer object first and if i don't do it?

There is no way you need to be that specific. I'm guessing, at the very most, this:

$('#customers td [name="selectedCustomers"]')

... which should improve performance. Next, if you're actually querying for selectedCustomers each time, you should cache the whole thing:

var selectedCustomers = $('#customers td [name="selectedCustomers"]');

Otherwise, if the name is dynamic, and you only have one item with the same name per page...

var item = $(document.getElementsByName(someName)[0]);

Caching just $('#customers') , on the other hand, is pretty much pointless. .find on customers will do just as much work as the whole selector in the first place, especially with querySelector support.

You seem to be missing the fundamental point of caching the object. Once the object is cached, any further traversal or manipulation within that selector will be performed on the stored object and doesn't require a search of the DOM to first locate the selector and create the collection every time you need to use it

Every time you call $("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']") a search of the document has to be performed to create the collection of elements before any changes can be made to the collection.

Caching the collection means no further searches need to be made therefore improving performance

/* locate and store the collection once*/
var $checkboxes=$("#customers tbody input[name='selectedCustomers']");
/* look within previously stored collection*/
$checkboxes.filter(/* expression*/ ).doSomething();

Using document.getElementById will be faster than a jQuery search, simply because it doesn't require addiitonal function calls made by jQuery library. However if you wish to use result as a jQuery object like: $( document.getElementById('foo')) the gains are likely not worth worrying about for a single use to cache an object

So I am saving myself from unnecessary multiple document.getElementById but the rest will be the same.

Yes. But maybe also no, as selectors are evaluated from right to left (see this article or this SO question ). And assuming an efficient engine, it had less work to do if it does that evaluation only on a part of the document tree if you first select #customers and then .find() in it. But I'm not 100% sure about that.

Is document.getElementById a more costly operation?

No, it is very cheap. Ids are the standard attribute to identify single elements, and browsers will build very performant lookup tables for it - you can assume it to be nearly O(1) .

customer.find("tbody tr td input[type='checkbox'][name='selectedCustomers']")

On the other hand, DOM selector queries which need to evaluate the DOM tree are very costly, especially if done manually in JS code (jQuery sizzle) and not native - though this rather simple query will be delegated to the native querySelectorAll .

I am guessing that #customers is your table element. So for performance, omit the tbody tr td tags, they are obligatory (assuming you have not used them to explicitly exclude checkboxes from <thead> / <tfoot> or <th> elements). You will not find an <input> as a direct child of a table element anyway - and the selector engine has much less to do.

Further, if you know your markup well and can make the assumption that only checkboxes have that name attribute, you might omit the tagname and type attribute selectors as well. And that means you can delegate to the native getElementsByName , which should boost performance a little bit again:

$(document.getElementById("customers").getElementsByName("selectedCustomers"))

If you need to check for the elements to be checkboxes, you still could filter them. With that, you might end up with

$(customer.get(0).getElementsByName("selectedCustomers")).filter(":checkbox")

However, to proof the performance gains you only can test, test, test; and you'll need to do that on your actual full page.

http://jsperf.com/different-jquery-selector-tests

Check out this little test. Basically $('#div').find('#p'); is the fastest and $('div').find('#p'); is the slowest.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM