querySelectorAll - whole vs split (v2)

Revision 2 of this benchmark created by Stefan Charsley on


Description

I want to see the performance difference between whole queries and segmented queries. Yes, split queries will return DOM elements in a different order because of query splitting.

Preparation HTML

<script>
var 
selector1 = "div",
selector2 = "#find1",
selector3 = "#find1 span span",
selector4 = ".span1",
selector5 = "#find1 span span, #find1 b",
selector6 = ".span1, #find1 b span",
selector7 = ".span1, #find1 span span",
idSelectorRE = /^#([\w-]*)$/,
tagclassSelectorRE = /^(?:([\w]+)|([\w]+)?\.([\w\-]+))$/,
selectorGroupRE = /(([^,]*([\[].*?[\]]))|([^,].*?))+/g,
doc = window.document

function merge ( first, second ) {
        var len = +second.length,
            j = 0,
            i = first.length
        for ( ; j < len; j++ ) first[i++] = second[j]
        first.length = i
        return first
    }

function qsa1 (selector) {

                var match, node, ret, m, i, j

                // ID
                if (match = idSelectorRE.exec(selector)) {
                        return (node = doc.getElementById(match[1])) ? [node] : []

                // Tag, Class, and Tag.Class
                } else if (match = tagclassSelectorRE.exec(selector)) {

                        // Tag
                        if (m = match[1])
                                return merge([], doc.getElementsByTagName(m))

                        m = match[3];

                        // Class
                        if (!match[2])
                                return merge([], doc.getElementsByClassName(m))

                        // Tag.Class
                        return merge([], doc.querySelectorAll(selector))

                // Multiple selectors / complex selectors
                } else if (match = selector.match(selectorGroupRE)) {
                        ret = []

            return merge(ret, doc.querySelectorAll(match[0]))

        // All other selectors
                } else {
                    return merge([], doc.querySelectorAll(selector))
                }
}

function qsa2 (selector) {

                var match, node, ret, m, i, j

                // ID
                if (match = idSelectorRE.exec(selector)) {
                        return (node = doc.getElementById(match[1])) ? [node] : []

                // Tag, Class, and Tag.Class
                } else if (match = tagclassSelectorRE.exec(selector)) {

                        // Tag
                        if (m = match[1])
                                return merge([], doc.getElementsByTagName(m))

                        m = match[3];

                        // Class
                        if (!match[2])
                                return merge([], doc.getElementsByClassName(m))

                        // Tag.Class
                        return merge([], doc.querySelectorAll(selector))

                // Multiple selectors / complex selectors
                } else if (match = selector.match(selectorGroupRE)) {
                        ret = []

            if (match.length == 1) return merge(ret, doc.querySelectorAll(match[0]))

                        for (i = 0; node = match[i]; i++)
                                Array.prototype.push.apply(ret, qsa2(node))
                        return ret

        // All other selectors
                } else {
                    return merge([], doc.querySelectorAll(selector))
                }
        }
</script>

<div id="find1">
<b><span>1</span></b>
<span>2</span>
<span class="span1">3</span>
<span><span>4</span></span>
</div>

Test runner

Ready to run.

Testing in
TestOps/sec
whole
qsa1(selector1)
qsa1(selector2)
qsa1(selector3)
qsa1(selector4)
qsa1(selector5)
qsa1(selector6)
qsa1(selector7)
ready
split
qsa2(selector1)
qsa2(selector2)
qsa2(selector3)
qsa2(selector4)
qsa2(selector5)
qsa2(selector6)
qsa2(selector7)
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.

  • Revision 2: published by Stefan Charsley on