Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimizing jQuery selector / addBack() when dealing with a large collection

I use jQuery to intentionally remove css classes from elements in a potentially large html table. See below for an explanation why I am doing that.

Currently I am doing it like this:

var tableElements = $("#TreeListElemente").find("*").addBack();
tableElements.removeClass("dxtl dxtl__B2 dxtl__B0 dxtlSelectionCell dxtlHeader dxtl__B3 dxtlControl dx-wrap dxtl__IM dxeHyperlink");

The table sometimes is large and has many elements. I would like to speed up the page load / DOM manipulation.

The IE's built-in Javascript profiler tells me that especially the .addBack() is slow. It seems to do some kind of sorting, which is totally unnecessary to my use case. Could I get rid of that? Is there another way to include the selected element itself, besides addBack()?

IE javascript profiler tree view

IE javascript profiler: Execution time for a collection of about 60000 elements. The inclusive times are in the third column

Or is there another, more efficient way to remove classes from a large set of elements, with selecting an element, itself, and all children?

Note: Why am I doing this: I am using the DevXpress TreeList Component which comes with it's own styling. There is no easy way to "unstyle it" on the server side, thus I chose to do that client-side, the way demonstrated above. In the end, I am selecting the TreeList, all child elements, and remove the relevant css classes from them.

Update/Solution 1

I have successfully implemented the solution proposed by Frédéric Hamidi an got quite an improvement:

IE javascript profiler tree view

IE javascript profiler: Execution time for a collection of about 60000 elements, using the proposal by Frederic. The inclusive times are in the third column

The time needed for the addBack() operation are just gone, remaining just the other stuff. This means an improvement by more than factor 4 overall. Yay!

Update/Solution 2

I have also implemented the solution proposed by A. Wolff and got a slight additional improvement:

IE javascript profiler tree view

IE javascript profiler: Execution time for a collection of about 60000 elements, using the proposal by A. Wolff. The inclusive times are in the third column

The time needed for the find() operation is gone, remaining just the other stuff again. This means an slight improvement of some 10s of milliseconds on my machine. Cool!

This is the solution I am using now:

$("#TreeListElemente, #TreeListElemente [class]").removeClass("dxtl dxtl__B2 dxtl__B0 dxtlSelectionCell dxtlHeader dxtl__B3 dxtlControl dx-wrap dxtl__IM dxeHyperlink");
like image 345
Marcel Avatar asked Dec 18 '15 14:12

Marcel


2 Answers

addBack() does perform a sort to put the matched elements in document order. The easy alternative, add(), does the exact same thing, so it won't solve your problem.

However, the documentation is helpful enough to provide a solution:

To create a jQuery object with elements in a well-defined order and without sorting overhead, use the $(array_of_DOM_elements) signature.

Therefore, to avoid that overhead, you can write:

var ancestor = $("#TreeListElemente"),
    tableElements = $(ancestor.find("*").get().concat(ancestor[0]));

get() and concat() end up building two arrays under the hood, though, so it will affect performance. The end result may be faster than your current approach, depending on the number of elements you match.

like image 161
Frédéric Hamidi Avatar answered Oct 18 '22 20:10

Frédéric Hamidi


The relevant selector to select element with ID TreeListElemente and all its descendants would be:

"#TreeListElemente, #TreeListElemente *"

Now you could filter out descendants having class:

"#TreeListElemente, #TreeListElemente [class]"

So it would give:

$("#TreeListElemente, #TreeListElemente [class]").removeClass("dxtl dxtl__B2 dxtl__B0 dxtlSelectionCell dxtlHeader dxtl__B3 dxtlControl dx-wrap dxtl__IM dxeHyperlink");
like image 31
A. Wolff Avatar answered Oct 18 '22 19:10

A. Wolff