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
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
Share Improve this question edited Mar 3, 2011 at 11:10 Felix Kling 817k181 gold badges1.1k silver badges1.2k bronze badges asked Mar 3, 2011 at 11:06 nzymenzyme 1852 silver badges9 bronze badges 8- Does the number of rows make a difference (Have you tested this)? You're only manipulating the table header. How many columns are there? You should use a filter rather than a find. groups.google./group/jquery-en/browse_thread/thread/… and learningjquery./2006/12/how-to-get-anything-you-want-part-2 – Shiv Kumar Commented Mar 3, 2011 at 11:10
-
1
What is
this
? What is the context? A jsfiddle would be great :) – Felix Kling Commented Mar 3, 2011 at 11:10 - Sorry, 'this' is a reference to the table I'm applying the plugin to – nzyme Commented Mar 3, 2011 at 11:14
-
You could try:
$tblhfixed.find("th").width(function(i, val) { return val;});
– Felix Kling Commented Mar 3, 2011 at 11:18 - 1 Did you ever find a solution? I'm chasing almost exactly the same problem and am suspecting jQuery's width() method which appears to be taking ~35 seconds for <6,000 elements. – Tom Morris Commented Sep 12, 2012 at 17:49
5 Answers
Reset to default 2I 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();
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());
}
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";
}
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());
it appears that $.width() is 99 times slower than the native get(0).clientWidth, check out this test: http://jsperf./jq-width-vs-client-width