QSA perf in IE

JavaScript performance comparison

Revision 3 of this test case created by Jakob

Preparation code

<div class='adiv'>
  test text inside a div!
</div>
<div class='adiv'>
  test text inside a div!
</div>
<div>
  <div>
    <div class='thediv'>
      test test test test test test
      <span>
        this is a span
      </span>
    </div>
  </div>
</div>
<div class='adiv'>
  test text inside a div!
</div>
<div class='adiv'>
  test text inside a div!
</div>
<div class='adiv'>
  test text inside a div!
</div>

Preparation code output

test text inside a div!
test text inside a div!
test test test test test test this is a span
test text inside a div!
test text inside a div!
test text inside a div!

Test runner

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

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
control
/*
Get Elements By ClassName
http://robertnyman.com/2008/05/27/the-ultimate-getelementsbyclassname-anno-2008/

This is a baseline metric. Since IE7 doesn't even have a getElementsByClassName, this is the _FASTEST_ anything could possibly get. It's all downhill from here.
*/


/*
        Developed by Robert Nyman, http://www.robertnyman.com
        Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/

var getElementsByClassName = function(className, tag, elm) {
    if (document.getElementsByClassName) {
      getElementsByClassName = function(className, tag, elm) {
        elm = elm || document;
        var elements = elm.getElementsByClassName(className),
            nodeName = (tag) ? new RegExp("\\b" + tag + "\\b", "i") : null,
            returnElements = [],
            current;
        for (var i = 0, il = elements.length; i < il; i += 1) {
          current = elements[i];
          if (!nodeName || nodeName.test(current.nodeName)) {
            returnElements.push(current);
          }
        }
        return returnElements;
      };
    } else if (document.evaluate) {
      getElementsByClassName = function(className, tag, elm) {
        tag = tag || "*";
        elm = elm || document;
        var classes = className.split(" "),
            classesToCheck = "",
            xhtmlNamespace = "http://www.w3.org/1999/xhtml",
            namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace) ? xhtmlNamespace : null,
            returnElements = [],
            elements, node;
        for (var j = 0, jl = classes.length; j < jl; j += 1) {
          classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
        }
        try {
          elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
        } catch (e) {
          elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
        }
        while ((node = elements.iterateNext())) {
          returnElements.push(node);
        }
        return returnElements;
      };
    } else {
      getElementsByClassName = function(className, tag, elm) {
        tag = tag || "*";
        elm = elm || document;
        var classes = className.split(" "),
            classesToCheck = [],
            elements = (tag === "*" && elm.all) ? elm.all : elm.getElementsByTagName(tag),
            current, returnElements = [],
            match;
        for (var k = 0, kl = classes.length; k < kl; k += 1) {
          classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
        }
        for (var l = 0, ll = elements.length; l < ll; l += 1) {
          current = elements[l];
          match = false;
          for (var m = 0, ml = classesToCheck.length; m < ml; m += 1) {
            match = classesToCheck[m].test(current.className);
            if (!match) {
              break;
            }
          }
          if (match) {
            returnElements.push(current);
          }
        }
        return returnElements;
      };
    }
    return getElementsByClassName(className, tag, elm);
    };

window.SELECT = function(str) {
  return getElementsByClassName(str);
}

var result = window.SELECT("thediv");
if (result.length != 1) {
  throw new Error("mismatch. wanted 1, found: "+result.length);
}
pending…
LeRoy
/*
LeRoy Expression Adaptation
http://weblogs.asp.net/bleroy/archive/2009/08/31/queryselectorall-on-old-ie-versions-something-that-doesn-t-work.aspx

This is a polyfill approach for document.querySelector. It adds an inert rule of "foo:bar" to all elements matching the selector. It can then use document.all to find computed styles that match foo:bar. The hypothesis is that document.all can be fast enough to offset the CSS engine pain.
*/


(function() {
  var style = document.styleSheets[0] || document.createStyleSheet();
  window.SELECT = function(selector) {
    style.addRule(selector, "foo:bar");
    var all = document.all,
        resultSet = [];
    for (var i = 0, l = all.length; i < l; i++) {
      if (all[i].currentStyle.foo === "bar") {
        resultSet[resultSet.length] = all[i];
      }
    }
    style.removeRule(style.rules.length - 1);
    return resultSet;
  }
})();

var result = window.SELECT('body > div > div > div[class="thediv"] > span');
if (result.length != 1) {
  throw new Error("mismatch. wanted 1, found: "+result.length);
}
pending…
Ajaxian Person
/*
http://www.ajaxian.com

Another polyfill. This one uses expressions to collect matching nodes. Based on some additional feedback, it sets the expression element in a way that auto-removes it. This should help performance.
*/

window.SELECT = function(selector) {
  var head = document.documentElement.firstChild;
  var styleTag = document.createElement("STYLE");
  head.appendChild(styleTag);
  document.__qsResult = [];

  styleTag.styleSheet.cssText = selector + "{zoom:expression(this.runtimeStyle.zoom='1',document.__qsResult.push(this))}";
  window.scrollBy(0, 0);
  head.removeChild(styleTag);

  var result = [];
  for (var i in document.__qsResult)
  result.push(document.__qsResult[i]);
  return result;
}

var result = window.SELECT('body > div > div > div[class="thediv"] > span');
if (result.length != 1) {
  throw new Error("mismatch. wanted 1, found: "+result.length);
}
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