Reputation: 185
I'm using a jquery plugin which fixes the headers on a html table that I generate. Unfortunately the performance of the plugin is very slow and I've narrowed it down to the following code:
var $tbl = $(this);
var $tblhfixed = $tbl.find("thead");
$tblhfixed.find("th").each(function ()
$(this).css("width", $(this).width());
});
This is taking about 40 seconds on a table with 2,000 rows in ie. Does anyone know why it's so slow and more importantly how can I make this faster? I've tried many other plugins and this is the only one which works how I want it to. Thanks for any help
Upvotes: 6
Views: 2532
Reputation: 10930
it appears that $.width() is 99 times slower than the native get(0).clientWidth, check out this test: http://jsperf.com/jq-width-vs-client-width
Upvotes: 1
Reputation: 14746
you should not repeat $(this)
inside your function passed into .each()
. wrapping an element has non-trivial overhead, which is not ok when you have 20k elements. you want to eliminate as much work as possible inside the .each()
call, or eliminate it altogether.
Also, why query find()
twice, when you can do this instead, which should give you the same results:
$ths = $('table thead th'); //or tableid, or something
$ths.css('width', $ths.width());
Upvotes: 1
Reputation: 1782
I guess you faced with the same problem that I had some time ago. It called a "Recalculate layout" or something.
Try to separate this script onto two loops, like this:
var $tbl = $(this);
var $tblhfixed = $tbl.find("thead");
var widths = [];
// 1.
$tblhfixed.find("th").each(function ()
widths.push($(this).width());
});
// 2.
$tblhfixed.find("th").each(function (index, element)
$(this).css("width", widths[index]);
});
First one will calculate all the widths. Second one will apply them to TH's
UPD: You may increase performance by placing this code between 1. and 2.:
$tblhfixed.hide();
and show it again after 2.:
$tblhfixed.show();
Upvotes: 2
Reputation: 2164
First, you should use find()
only when you need to pass through all nested nodes. Right here you can use children()
.
Second, each time $(this)
creates new instance of jQuery object, while you can create it once:
var $this = $(this);
Each time $(this).width()
is recalculated. Make sure that you need it to be recalculated. Or do:
var tableWidth = $this.width();
And third, according to @Martin Jespersen, each iteration the function
object is created.
Also you don't need jQuery here at all. You can access DOM directly:
var tableWidth = ...; // get the table width the way you want
var thead = this.tHead;
var thRow = thead.rows[0];
for (var i = 0; i < thRow.length; ++i) {
thRow.cells[i].style.width = tableWidth + "px";
}
Upvotes: 1
Reputation: 26183
the culprit is probably the .each
.
The reason is that when you iterate using .each
instead of a normal loop, you call a function for each iteration. a function call has a pretty big overhead in this case, since a new callstack has to be created for each iteration.
To make it faster change
$tblhfixed.find("th").each(function ()
$(this).css("width", $(this).width());
});
to
var elms = $tblhfixed.find("th");
for(var i=0, elm;elm = elms[i];i++) {
elm.css("width", elm.width());
}
Upvotes: 1