简体   繁体   中英

JQuery addClass and removeClass efficiency

I am building a sortable table and need the update the 'sort order' icons on the table header.

Here is a little information so you can better understand what my code is doing.

The code is being executed from within a click event, and $(this) references the table header cell being clicked.

The table header cell has three spans in it; a wrapper, a text span, and a icon span. Here is how it looks

<span class='ui-button ui-widget ui-state-default ui-button-text-icon-secondary'>
  <span class='ui-button-text'>text</span>
  <span class='ui-button-icon-secondary ui-icon ui-icon-triangle-2-n-s'></span>
</span>

collection is a return from $("thead:first th")

and here is my code that does the switch on the icons.

var new_class = sort_info.order == "asc" ? "ui-icon-triangle-1-n" : "ui-icon-triangle-1-s";
collection.find(".ui-icon").removeClass("ui-icon-triangle-1-n ui-icon-triangle-1-s ui-icon-triangle-2-n-s").addClass("ui-icon-triangle-2-n-s");
$(this).find(".ui-icon").removeClass("ui-icon-triangle-1-n ui-icon-triangle-1-s ui-icon-triangle-2-n-s").addClass(new_class);

as you can see it selects all header icon cells, removes any icon classes that may exist, then re-adds the applicable class. THEN i grab the clicked cells' icon, remove any icon classes, and apply the appropriate class.

Is this the best way to do this? It works.. and it executes in roughly 7 ms (Windows 7, FF6.0) which is ok by me.. just looks like it's a lot of work being done.

any thoughts?

If you don't have any other dynamic classes being assigned to these objects, then you can replace o.removeClass().addClass() with o.attr("className", xxx) since you know what the final result should be and you can speed it up by a factor of 3x (in my test case).

With your HTML and your code, I think it could be reduced to this:

var new_class = sort_info.order == "asc" ? "ui-icon-triangle-1-n" : "ui-icon-triangle-1-s";
collection.find(".ui-icon").attr("className", "ui-button-icon-secondary ui-icon ui-icon-triangle-2-n-s"); 
$(this).find(".ui-icon").attr("className", "ui-button-icon-secondary ui-icon " + new_class);

This should be faster because there's half as many jQuery calls and just setting an attribute is way faster than addClass() and removeClass() , but it is also more brittle and a bit less readable for what changes you're actually trying to make. If you ever decide to add more classes to these objects, this code will have to be modified to account for them. Only you can decide if this additional performance is worth a little reduction in maintainability.

You could reduce the number of selector operations by doing just one selector operation and then iterating over it with a custom function to decide whether each object is under this or not and assign it an appropriate className. This both reduces the number of DOM searches, but also prevents duplicate assignment of className. That would look something like this:

var new_class = sort_info.order == "asc" ? "ui-icon-triangle-1-n" : "ui-icon-triangle-1-s";
var that = this;
collection.find(".ui-icon").each(function() {
    if ($.contains(that, this)) {
        this.className = "ui-button-icon-secondary ui-icon " + new_class;
    } else {
        this.className = "ui-button-icon-secondary ui-icon ui-icon-triangle-2-n-s";
    }
});

Putting all three of these into a jsperf test with only 10 items in the iteration, I get this in Chrome:

Your method: 6691 ops/sec
Direct set of className: 11,210 ops/sec
Iteration with single selector: 20,280 ops/sec

I get an even more dramatic difference in Firefox 6 (your method is even slower, my fast method is even faster).

So, it does appear things can be made to go a lot faster than what you have if that's relevant in your app.

I think it won't matter much, but maybe this is faster (and you know how to measure it, so I'll let you be the judge):

var new_class = sort_info.order == "asc" ? "ui-icon-triangle-1-n" : "ui-icon-triangle-1-s";
collection.not(this).find(".ui-icon-triangle-1-n, .ui-icon-triangle-1-s").removeClass("ui-icon-triangle-1-n ui-icon-triangle-1-s").addClass("ui-icon-triangle-2-n-s");
$(this).find(".ui-icon").removeClass("ui-icon-triangle-1-n ui-icon-triangle-1-s ui-icon-triangle-2-n-s").addClass(new_class);

But it won't matter that much afaik.

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