Stephen
Stephen

Reputation: 18964

jQuery: What is more efficient? Many ID specific selectors, or one "Contains Prefix Selector"

I have a snippet of JavaScript in a project that caches an array of jQuery objects (anchor tags) on a dashboard:

$.extend(cache, {
    dashboard : {
        buttons : [
            $('#dash-new-lead'),               $('#dash-jobs-calendar'),
            $('#dash-view-lead'),              $('#dash-sales-reports'),
            $('#dash-search-leads'),           $('#dash-new-job'),
            $('#dash-dispatch-jobs'),          $('#dash-dispatch-reports'),
            $('#dash-manage-employees'),       $('#dash-manage-trucks'),
            $('#dash-finalize-jobs'),          $('#dash-payment-profiles'),
            $('#dash-employee-statements'),    $('#dash-company-statements'),
            $('#dash-finance-reports'),        $('#dash-admin-sources'),
            $('#dash-admin-statuses'),         $('#dash-admin-companies'),
            $('#dash-admin-groups'),           $('#dash-admin-users'),
            $('#dash-admin-dispositions'),     $('#dash-search-jobs'),
            $('#dash-jobs-calendar-dispatch'), $('#dash-new-lead-dispatch'),
            $('#dash-finance-notices')
        ]
    }
});

Each link is styled later (using $.each) as a button. Each link gets a unique jQuery UI icon (hence the id's instead of just a class selector). Depending on a user's access level some links may or may not exist in the DOM.

I'm wondering now if it would be more efficient to use jQuery's Contains Prefix Selector:

$.extend(cache, {
    dashboard : {
        buttons : $('a[id|="dash-"]')
    }
});
  1. Pro: Fewer references to the jQuery Object = faster
  2. Con: jQuery cannot use document.getElementByID = slower

Upvotes: 2

Views: 409

Answers (4)

Shai
Shai

Reputation: 21

As well as each of your elements having its unique id (dash-new-jobs etc), give it a class too (class='dash-button').

You can then refer to the whole collection efficiently using e.g.

$.extend(cache, {
    dashboard : {
        buttons : $('.dash-button')
    }
});

And if you need to give them all different icons like you mentioned, use their unique ID:

$('.dash-button').each(function() {
    // do something based on $(this).attr('id'),
    // which will be dash-new-job/dash-whatever
});

Efficient (though as the others have said, do performance tests if you're unsure!), and clean/easy to understand code (much cleaner than using 'contains' selector!).

Upvotes: 2

user113716
user113716

Reputation: 322492

It'll depend very much on the browser, so you'll need to test to be sure.

Because 'a[id|="dash"]' (notice I removed the -) appears to be a valid querySelectorAll() selector, any browsers that support that method (which includes IE8) should have very good performance.

Because you're including the tagName, browsers that don't support querySelectorAll() will (I believe) use getElementsByTagName(), so the filter will only be applied to the <a> elements it finds.

It should help as well if you're able to limit the query to a narrower context than the document.

Note also that according to this test, the performance of getElementById() isn't terribly exciting in IE6 and IE7. And again IE8 does support querySelectorAll(), though it wouldn't be bad to make sure it succeeds with that particular selector. If not, the query will default to Sizzle's engine.


Here's a test using that selector directly through querySelectorAll(). You can run it in different browsers to see where it is supported.


Note also that getElementsByClassName() isn't supported before IE9, so I doubt that using a class will offer any great performance improvements over 'a[id|="dash"]'. The exception being Firefox3, which does support getElementsByClassName(), and not querySelectorAll().

Upvotes: 2

Surreal Dreams
Surreal Dreams

Reputation: 26380

I'd suggest you go with the contains prefix method because it's easier to maintain. You set it up this way and you no longer need to worry about which ids to select, you just target the group that's there and you're done.

While the id method will likely have better performance, you're creating a jQuery object for each one. That's got to have an impact too.

Upvotes: 1

Guffa
Guffa

Reputation: 700272

You can make a single selector that contains all the identities:

$.extend(cache, {
  dashboard : {
    buttons : $('#dash-new-lead,#dash-jobs-calendar,#dash-view-lead,#dash-sales-reports,#dash-search-leads,#dash-new-job,#dash-dispatch-jobs,#dash-dispatch-reports,#dash-manage-employees,#dash-manage-trucks,#dash-finalize-jobs,#dash-payment-profiles,#dash-employee-statements,#dash-company-statements,#dash-finance-reports,#dash-admin-sources,#dash-admin-statuses,#dash-admin-companies,#dash-admin-groups,#dash-admin-users,#dash-admin-dispositions,#dash-search-jobs,#dash-jobs-calendar-dispatch,#dash-new-lead-dispatch,#dash-finance-notices')
  }
});

I would however consider adding a class to the buttons so that it's easy to target them using a simple selector. That would make it easier to maintain the code.

Upvotes: 3

Related Questions