Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery: add() performance; is there a better way?

What I want to do: Group all the like elements on a page (of a certain kind) into an object which I can later iterate on -- or apply sweeping changes to every element within.

My code is successful at accomplishing the given task but when the number of elements grows to 200-300+ then the performance drastically drops off and users have noticed. I have isolated the offending lines of code and want to know if there is another way of accomplishing the same problem.

The add() function appears to be the problematic operation based on timers I have placed around them. At first the time required to perform the operation is .001 but grows until the number of elements reaches 300 and it takes ~.1 of a second for each additional element AND continues slowing down.

I have researched (and more) for jQuery performance enhancing abilities and have implemented a few of them (namely 3) but they have not given me any meaningful performance increases. Amazingly, this code performs within 1 second (!) for Firefox (300+ calls to add()) while Chrome and IE take roughly 10-20x longer or more...

Here is my code:

rowsToChange = $([]);
// Grab all the ids greater than whichever one I'm currently looking at:
var arr = $.makeArray($("[id^=stackLocatorLinkFillUp]:gt("+(uniqueID-1)+")"));
for (var i=0; i<arr.length; i++) {
    $this = arr[i];
    // <<< VARIOUS CONDITIONALS that make this as selective as possible REMOVED >>>
    startTimer = new Date().getTime();
    // **************************
    // PROBLEMATIC LINE FOLLOWS when 200+ records:
    rowsToChange = rowsToChange.add($this);
    // Grows from .001 to .1xx after 300 iterations
    console.log("innertiming:"+(new Date().getTime() - startTimer)/1000);
    // **************************
}

The end result looks like this (via Chrome Inspector):

[<div style=​"display:​none" id=​"stackLocatorLinkFillUp1">​itemType=BOUND&ccLocale=PERIODICAL​</div>​, 
<div style=​"display:​none" id=​"stackLocatorLinkFillUp2">​itemType=BOUND&amp;ccLocale=PERIODICAL​</div>​,
...
]

Eventually I process all these as follows (which I love the simplicity of!):

var superlink = "...new <a> goodness to display for all elements...";
rowsToChange.html(superlink).css("display","block");

This looked like it could be a valid solution (different add method?) but I would prefer to continue gathering a list of objects together so that the last line can work its magic.

(am not i am pointed out that the following is not true -- regarding concatenation; thanks 'am not i am')

It seems like the add() operation must be concatenating strings since that appears to be one of the main problems others face. But transforming my add() statement into += doesn't look like it works.

Thanks for checking this out;

Chrome: 18.0.1025.142 m Firefox: 11.0 IE: 8.0.7600.16385

like image 500
veeTrain Avatar asked Apr 05 '12 19:04

veeTrain


1 Answers

First observation: add saves the previous element set. Try rowsToChange = jQuery.merge(rowsToChange, [$this]); instead.

Second observation: it seems as though rowsToChange will end up being the exact same element set as the one you called $.makeArray on. Why not just save the original set?

like image 73
DCoder Avatar answered Sep 22 '22 21:09

DCoder