Tutorial :What's the fastest way to select a large amount of checkboxes and de/select them?



Question:

Since I use jQuery 1.3+ all except one timed test is using that. The other is plain javascript I found from back in 2000. I stopped going that route as it was taking around 150 seconds to run the test. I've read quite a few jQuery optimization web pages that relate to selecting a single element. A '#id' is the best case for using that, but now I have the issue of checking all checkboxes in one column in a rather large table that has multiple checkbox columns.

What I have done is setup a page the creates 20,000 table rows with two check box columns. The goal is to check the second column see how long that took, and then uncheck them and see how long that took. Obviously we want the lowest time. I'm only using IE6 and 7 and in my case all of my users will be doing the same.

20,000 rows you say? That's what I said too, but this is going to production (out of my hands) and it's too late to change now. I'm just trying to throw a hail mary with 1 second left on the clock. Besides, I've learned that input.chkbox isn't the fastest selector (for IE7)! :)

The question is, is there a better way to do this jQuery or otherwise? I'd love it to be running in less than half a second on my machine.

So you don't have to retype all the crap I've already done here's the test stuff I came up with:

Updated Morning 4/14 to include further time trials:

<form id="form1" runat="server">  <div>                     <a href="#" id="one">input[id^='chkbox'][type='checkbox']</a><br />          <a href="#" id="two">#myTable tr[id^='row'] input[id^='chkbox'][type='checkbox']</a><br />          <a href="#" id="three">#myTable tr.myRow input[id^='chkbox'][type='checkbox']</a><br />          <a href="#" id="four">tr.myRow input[id^='chkbox'][type='checkbox']</a><br />          <a href="#" id="five">input[id^='chkbox']</a><br />          <a href="#" id="six">.chkbox</a><br />          <a href="#" id="seven">input.chkbox</a><br />          <a href="#" id="eight">#myTable input.chkbox</a><br />            <a href="#" id="nine">"input.chkbox", "tr"</a><br />          <a href="#" id="nine1">"input.chkbox", "tr.myRow"</a><br />          <a href="#" id="nine2">"input.chkbox", "#form1"</a><br />          <a href="#" id="nine3">"input.chkbox", "#myTable"</a><br />            <a href="#" id="ten">input[name=chkbox]</a><br />          <a href="#" id="ten1">"input[name=chkbox]", "tr.myRow"</a><br />          <a href="#" id="ten2">"input[name=chkbox]", "#form1"</a><br />          <a href="#" id="ten3">"input[name=chkbox]", "#myTable"</a><br />            <a href="#" id="ten4">"input[name=chkbox]", $("#form1")</a><br />          <a href="#" id="ten5">"input[name=chkbox]", $("#myTable")</a><br />            <a href="#" id="eleven">input[name='chkbox']:checkbox</a><br />          <a href="#" id="twelve">:checkbox</a><br />          <a href="#" id="twelve1">input:checkbox</a><br />          <a href="#" id="thirteen">input[type=checkbox]</a><br />            <div>              <input type="text" id="goBox" /> <button id="go">Go!</button>              <div id="goBoxTook"></div>          </div>            <table id="myTable">              <tr id="headerRow"><th>Row #</th><th>Checkboxes o' fun!</th><th>Don't check these!</th></tr>              <% for(int i = 0; i < 20000;i++) { %>              <tr id="row<%= i %>" class="myRow">                  <td><%= i %> Row</td>                  <td>                      <input type="checkbox" id="chkbox<%= i %>" name="chkbox" class="chkbox" />                  </td>                  <td>                      <input type="checkbox" id="otherBox<%= i %>" name="otherBox" class="otherBox" />                  </td>              </tr>              <% } %>          </table>  </div>          <script type="text/javascript" src="<%= ResolveUrl("~/") %>Javascript/jquery.1.3.1.min.js"></script>          <script type="text/javascript">                $(function() {                                    function run(selectorText, el) {                                          var start = new Date();                                           $(selectorText).attr("checked", true);                                                    var end = new Date();                      var timeElapsed = end-start;                      $(el).after("<br />Checking Took " + timeElapsed + "ms");                        start = new Date();                                           $(selectorText).attr("checked", false);                                                   end = new Date();                      timeElapsed = end-start;                      $(el).after("<br />Unchecking Took " + timeElapsed + "ms");                  }                           function runWithContext(selectorText, context, el) {                                          var start = new Date();                                           $(selectorText, context).attr("checked", true);                                                   var end = new Date();                      var timeElapsed = end-start;                      $(el).after("<br />Checking Took " + timeElapsed + "ms");                        start = new Date();                                           $(selectorText, context).attr("checked", false);                                                      end = new Date();                      timeElapsed = end-start;                      $(el).after("<br />Unchecking Took " + timeElapsed + "ms");                  }                    $("#one").click(function() {                                              run("input[id^='chkbox'][type='checkbox']", this);                  });                    $("#two").click(function() {                      run("#myTable tr[id^='row'] input[id^='chkbox'][type='checkbox']", this);                  });                    $("#three").click(function() {                      run("#myTable tr.myRow input[id^='chkbox'][type='checkbox']", this);                  });                    $("#four").click(function() {                      run("tr.myRow input[id^='chkbox'][type='checkbox']", this);                  });                    $("#five").click(function() {                      run("input[id^='chkbox']", this);                  });                    $("#six").click(function() {                      run(".chkbox", this);                  });                    $("#seven").click(function() {                      run("input.chkbox", this);                  });                    $("#eight").click(function() {                      run("#myTable input.chkbox", this);                  });                    $("#nine").click(function() {                      runWithContext("input.chkbox", "tr", this);                  });                      $("#nine1").click(function() {                      runWithContext("input.chkbox", "tr.myRow", this);                  });                  $("#nine2").click(function() {                      runWithContext("input.chkbox", "#form1", this);                  });                  $("#nine3").click(function() {                      runWithContext("input.chkbox", "#myTable", this);                  });                    $("#ten").click(function() {                      run("input[name=chkbox]", this);                  });                                     $("#ten1").click(function() {                      runWithContext("input[name=chkbox]", "tr.myRow", this);                  });                    $("#ten2").click(function() {                      runWithContext("input[name=chkbox]", "#form1", this);                  });                    $("#ten3").click(function() {                      runWithContext("input[name=chkbox]", "#myTable", this);                  });                    $("#ten4").click(function() {                      runWithContext("input[name=chkbox]", $("#form1"), this);                  });                    $("#ten5").click(function() {                      runWithContext("input[name=chkbox]", $("#myTable"), this);                  });                    $("#eleven").click(function() {                      run("input[name='chkbox']:checkbox", this);                  });                    $("#twelve").click(function() {                      run(":checkbox", this);                  });                    $("#twelve1").click(function() {                      run("input:checkbox", this);                  });                    $("#thirteen").click(function() {                      run("input[type=checkbox]", this);                  });                    $('#go').click(function() {                      run($('#goBox').val(), this);                  });              });          </script>  </form>  


Solution:1

input[name=chkbox] is coming in as the fastest jQuery selector on my machine under IE7.

Unchecking Took 2453ms  Checking Took 2438ms  Unchecking Took 2438ms  Checking Took 2437ms  Unchecking Took 2453ms  Checking Took 2438ms  

input.chkbox and...

Unchecking Took 2813ms  Checking Took 2797ms  Unchecking Took 2797ms  Checking Took 2797ms  Unchecking Took 2813ms  Checking Took 2797ms  

input:checkbox.chkbox seem tied

Unchecking Took 2797ms  Checking Took 2797ms  Unchecking Took 2813ms  Checking Took 2781ms  

.chkbox almost takes twice as long as the input.chkbox

Unchecking Took 4031ms  Checking Took 4062ms  Unchecking Took 4031ms  Checking Took 4062ms  

The javascript for loop is by far the worst coming in at:

Checking Took 149797ms  

150 seconds! It locks the browser too. This just makes me really impressed with jQuery. I honestly didn't expect it to be that slow. Probably because I'm passing across each individual element which it's then having to find...

This was pretty interesting to me as well:

input[id^='chkbox']

Unchecking Took 3031ms  Checking Took 3016ms  

took less time than:

input[id^='chkbox'][type='checkbox']

Unchecking Took 3375ms  Checking Took 3344ms  

I thought since I posted more filters it'd be faster. Nope!

Specifying even more paths to the checkbox makes it way slower:

#myTable tr[id^='row'] input[id^='chkbox'][type='checkbox']

Checking Took 10422ms  

It didn't even run the second uncheck as it asked me if I wanted to continue running scripts on my computer. Crazy! :P

Update Morning 4/14:

Someone brought up setting the context: I actually did a few of those and much to my suprise and against what a lot of people have said on the web on IE7 these were slower! Here are the times I got with a few different context's specified paired with the quicker selector's above:

"input.chkbox", "tr"

Checking Took 8546ms  

"input.chkbox", "tr.myRow"

Checking Took 8875ms  

"input.chkbox", "#form1"

Unchecking Took 3032ms  Checking Took 3000ms  

"input.chkbox", "#myTable"

Unchecking Took 2906ms  Checking Took 2875ms  

Current winner (still): input[name=chkbox]

Unchecking Took 2469ms  Checking Took 2453ms  

"input[name=chkbox]", "tr.myRow"

Checking Took 9547ms  

"input[name=chkbox]", "#form1"

Unchecking Took 3140ms  Checking Took 3141ms  

"input[name=chkbox]", "#myTable"

Unchecking Took 2985ms  Checking Took 2969ms  

Update 2 Morning 4/14

Thought I might have had a better one after I noticed a syntax difference from http://beardscratchers.com/journal/jquery-its-all-about-context. It seems that these are NOT the same as they are giving slightly better times, but still doesn't beat the non-contexted selector - darn.

"input[name=chkbox]", $("#form1")

Unchecking Took 3078ms  Checking Took 3000ms  Unchecking Took 3078ms  Checking Took 3016ms  

"input[name=chkbox]", $("#myTable")

Unchecking Took 2938ms  Checking Took 2906ms  Unchecking Took 2938ms  Checking Took 2921ms  

Update 3 Morning 4/14

Russ wanted me to try these out, they de/select ALL the boxes but again it was interesting:

:checkbox

Unchecking Took 8328ms  Checking Took 6250ms  

input:checkbox

Unchecking Took 5016ms  Checking Took 5000ms  

-> Fastest?!?! input[type=checkbox]

Unchecking Took 4969ms  Checking Took 4938ms  

The fact that the third up there is the fastest is quite interesting as that goes against what I would have thought. Why wouldn't (for IE7 at least) the :checkbox just use the type=checkbox to achieve a faster time? These are really close scores but the checking took 62ms less time. Also, why are the first two different at all? Is there a different element besides an input that can take have a checkbox?


Solution:2

I haven't tested this, but you could try building an array[] of checkbox references on page load then simply iterate over that each time you want to make a change?

You'd pay the performance cost on page load, but it might be quicker than walking the DOM each time. Hey, at least you'd be performing the heavy lifting in user 'down time' (how long does it take for people to locate and click the unselect/select options).


Solution:3

My only suggestion probably wont work either. Switch browsers. But I've only had one company actually agree to that. We had the company switch to FireFox, and specific users move to Google Chrome. IE is just too slow with JavaScript.

Also, you can try pre-caching the jquery query list.

If all else fails, solve it with psychology. That means letting the user know that something is going to take a long time. Put up a "Please wait" div while the function is performing. That way the user knows that the browser isn't just locked up, and they know when they can get back to work. I have had many a slow page "solved" by doing just this.


Solution:4

Have you tried the jQuery selectors with a context to see if that improves performance? Presumably the controls will be inside of an ASP.NET form, and perhaps another uniquely identifiable element?

For example, where you have

$("input[id^='chkbox']")  

Try with

$("input[id^='chkbox']", "#myFormID")  

Here's a BeardScratchers article on context

EDIT:

Following your updates, it seems like 2.45-6 seconds might be the fastest that you can achieve, given your circumstances.

Just for completeness, have you tried the following selectors?

$(':checkbox')  $('input[type=checkbox]')  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »