views:

77

answers:

3

I have a web app where I have several elements with class="classA". I want to select and apply a function to all of them. I am doing the obvious thing, which is $(".classA").each(function () { ... }). This works just fine in Chrome/Safari/Firefox but is really slow in IE. It turns out IE has serious performance issues when selecting things by CSS class in jQuery.

I was wondering if anyone has suggestions on good ways to deal with this. I can't use ID selectors because there can be multiple DOM elements I want to select.

-- EDIT --

Below is my tests code.

  • test1 uses document.getElementById("id") and is very fast.

  • test2 uses $("#id") and is pretty slow.

  • test3 uses $(".class") and is even slower.

As far as I can tell, there is no native implementation of document.getElementsByClassName in IE8--I get an error when I try to use it.

<html>

    <head>
        <script type="text/javascript" src="jquery-1.4.2.js"></script>


        <script type="text/javascript">


            function test1 ()
            {
                var start = (new Date).getTime();
                for (var i = 0; i < 10000; i++)
                {
                    document.getElementById("test1");
                }
                var elapsed = (new Date).getTime() - start;
                alert("test1 elapsed: " + elapsed);
            }

            function test2 ()
            {
                var start = (new Date).getTime();
                for (var i = 0; i < 10000; i++)
                {
                    var x = $("#test2");
                }
                var elapsed = (new Date).getTime() - start;
                alert("test2 elapsed: " + elapsed);
            }

            function test3 ()
            {
                var start = (new Date).getTime();
                for (var i = 0; i < 10000; i++)
                {
                    $(".test3");
                }
                var elapsed = (new Date).getTime() - start;
                alert("test3 elapsed: " + elapsed);
            }

        </script>

    </head>

    <body>

        <div id="test1">test1</div>

        <div id="test2">test2</div>

        <div id="test3" class="test3">test3 1</div>
        <div id="test3" class="test3">test3 2</div>
        <div id="test3" class="test3">test3 3</div>
        <div id="test3" class="test3">test3 4</div>

        <input type="button" onclick="test1();" value="test1" />
        <input type="button" onclick="test2();" value="test2" />
        <input type="button" onclick="test3();" value="test3" />

    </body>

</html>
+1  A: 

I don't know if this will help, but if your elements are all the same tag (e.g. DIV) you could use a selector like "DIV.classA". jQuery may be able to optimize that with a call to getElementsByTagName.

If you can specify a parent element, e.g. $('DIV.classA', someParent), that would limit the scope of what's being searched, which may increase performance.

John Bledsoe
+2  A: 

You can try a variety of things, but IE is optimized to fetch elements by ID, nothing else (it puts elements IDs in a hashtable under the covers).

If you're generating your page via some server-side technology, you could determine the list of elements and then output a JavaScript array of the IDs of those elements, then when the page loads you could loop through that array and collect your elements by ID.

That's the approach we've taken with ASP.NET apps with good success, though you may be doing something else. I would at least investigate the options jmbledsoe has described, they can help a little, but I doubt you'll get the performance you're hoping for.

Cory Larson
@Cory - Regarding the IDs, better yet may be to have identical IDs *except* for a numeric (or other unique) suffix. No need to maintain and loop through an array. Just use a "starts with" selector, as in `[id^=someID]` to get `someID1 someID2 someID3` etc.
patrick dw
Yea, it looks like this is what I'll end up doing. A shame since it's quite a hacky solution...
Sam Lee
+7  A: 

Have a look at jQuery: Performance analysis of selectors:

Test 2 - Finding an element by Class

Although CSS classes are intended to be reused among elements, you might create some elements with a unique class name just to identify and retrieve them through javascript. This is exactly what we test in this second test by seaching the element whose class is "p-4781". We have four alternatives:

A - Using the class selector

$('.p-4781').html()

B - Using the class selector + tag

$('p.p-4781').html()

C - Using attribute search + tag

$('p[class="p-4781"]').html()

D - Using tag search + filter

$('p').filter('.p-4781').html()

After running this test for the first time in different browsers, I got:

   Firefox Opera    IE6     IE7    Safari
A     2891   641   1718     631      329
B      453    78    313     180       78
C      422   109    578     201      187
D      203   266    375     210       94

The table above shows case B as the fastest selector for most browsers (except Firefox). It is easy to understand why case A isn't efficient, since the code has to iterate over all elements of the DOM tree. Case C and D aren't that bad, but I would say case B should be the preferred one for this goal.

So use a tag name plus class name. It's way faster in older browsers.

cletus
+1 - Nothing like hard data to back up your answer.
patrick dw
Does jQuery perform any caching? If so, the order of the tests might be affecting the results.
CurtainDog
+1 Great answer @cletus
Doug Neiner
@CurtainDog - It doesn't, it's really Sizzle not jQuery (which *includes* Sizzle) doing this part, you can view the source here: http://github.com/jeresig/sizzle/blob/master/sizzle.js
Nick Craver