jQuery 1.4.3 perf degrade

JavaScript performance comparison

Revision 5 of this test case created by Charles McNulty

Info

This is my attempt to prove the regression in performance that occurred with in 1.4.4, with this commit. I've then applied this plugin to the third test to show how easy it is to bring 1.4.3 performance back into 1.6.

This bug has been closed as "wontfix", for the following stated reason:

Both the createRange and sourceIndex code branches failed on disconnected DOM nodes, nodes in separate DOM documents, and nodes in non-HTML documents. Replacing that code with this yields much better cross-platform results overall.

It should be noted, however that in my tests with disconnected DOM nodes within 1.5.2, all browsers produce nonsensical, and different results upon sorting (including different results within the same browser upon refreshing). Therefore, this change didn't appear to improve the situation for sorting disconnected nodes. I didn't do any tests regarding separate DOM documents (Does this refer to pulling in nodes from an iframe for instance?) nor non-HTML documents. What would be nice though, is test cases that demonstrate the problem. This plugin passes all of the unit tests as of the release of 1.5.2.

I don't deny that sourceIndex could be problematic, however, it's my belief that the performance decrease is severe enough under certain conditions in IE7/8 that we need some method of both preserving the sourceIndex method of sorting where we can, while also addressing whatever testable issues exist with sourceIndex. That would result, unfortunately in more code than was in 1.4.2, rather than less code as was committed, but if jQuery is serious in support for IE 6,7 and 8 serious consideration needs to be made to the performance of those browsers.

Preparation code

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>var a = jQuery.noConflict();</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"></script>
<script>var b = jQuery.noConflict();</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"></script>
<script>

(function($) {

 if ("sourceIndex" in document.documentElement) {

  var baseHasDuplicate = true,
      sortOrder = null;

  // Here we check if the JavaScript engine is using some sort of
  // optimization where it does not always call our comparision
  // function. If that is the case, discard the hasDuplicate value.
  //   Thus far that includes Google Chrome.
  [0, 0].sort(function() {
   baseHasDuplicate = false;
   return 0;
  });

  sortOrder = function(a, b) {
   if (!a.sourceIndex || !b.sourceIndex) {
    if (a == b) {
     hasDuplicate = true;
    }
    return a.sourceIndex ? -1 : 1;
   }

   var ret = a.sourceIndex - b.sourceIndex;
   if (ret === 0) {
    hasDuplicate = true;
   }
   return ret;
  };

  $.unique = function(results) {
   if (sortOrder) {
    hasDuplicate = baseHasDuplicate;
    results.sort(sortOrder);

    if (hasDuplicate) {
     for (var i = 1; i < results.length; i++) {
      if (results[i] === results[i - 1]) {
       results.splice(i--, 1);
      }
     }
    }
   }

   return results;
  };
 }
})(jQuery);


var c = jQuery.noConflict();</script>

<style>
.test {
   display: none;
}
</style>

<div id="items">  
</div>

<script>
  var amt = 50,
      $jq_142 = a('#items'),
      $jq_16 = b('#items'),
      $jq_16_with_fix = c('#items'),
      elems = [];
 
  for (var i = 0; i < amt; i++) {
   elems.push('<ul class="test"><li class="test">foo</li></ul>');
   elems.push('<div class="test">hmm</div>');
   elems.push('<input class="test" type="hidden" name="hoo' + i + '" /> ')
   elems.push('<select class="test"><option value="1">foo</option></select>')
  }
 
  $jq_142.html(elems.join(""));
  $jq_16.html(elems.join(""));
  $jq_16_with_fix.html(elems.join(""));
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
version 1.4.2
$jq_142.find('li').add('#items');
pending…
version 1.6
$jq_16.find('li').add('#items');
pending…
1.6 with fix
$jq_16_with_fix.find('li').add('#items');
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment