My application has a long list of objects whose width needs to be modified via jQuery. Currently I’m using code like this:
$('#my_list div.text_field').each(function() {
// Cache objects we're going to use multiple times.
var $textField = $(this);
var $listContents = $textField.closest('div.list_contents');
// Find widths.
var contentsWidth = $listContents.outerWidth();
var avatarsWidth = $listContents.find('div.avatars').outerWidth();
var tagsWidth = $listContents.find('div.tags').outerWidth();
var textLeft = $textField.position().left;
// Update the width.
var newTextWidth = contentsWidth - textLeft - avatarsWidth - tagsWidth;
$textField.css({ width: newTextWidth });
});
However, it takes a while (> 1 second) when there are hundreds of objects to be manipulated. Any idea how I could make this faster? Should I totally eschew jQuery and use native JS?
Okay, through a series of improvements I was able to whittle the time it takes to run this code (on Chrome 18 on a series of ~600 items) down from over 3000 ms to 70ms.
The most drastic improvement came from using offsetWidth on the raw HTML elements instead of jQuery’s outerWidth() statement. That alone shaved off over 50% of the time:
The second most drastic change came from reducing the number of DOM modifications I made. In the code above, I was looping through elements, calculating their widths, and then immediately applying these widths to the DOM. In my improved code, I still loop through to calculate the widths, however I then store those widths, detach the elements from the DOM, apply the stored widths, and reattach them. Thanks to @muffel for this idea. This shaved off over 30% of the total time:
The third biggest improvement came from reducing the number of times I traversed the DOM. Instead of selecting elements each time through the loop, I selected them all up front and then referenced the indices inside the loop. This made up the majority of the remaining improvement:
Hope this helps someone!