xpath-querySelector-vs-dom-traversal (v2)

Revision 2 of this benchmark created by rvmn on


Preparation HTML

<html><body>
<div></div>
<div>
    <ul>
       <li></li>
       <li></li>
       <li>got me</li>
       <li></li>
    </ul>
</div>
<script>
        function useDomTraversal(xpath) {
            var chunk = "",
                element = document.documentElement,
                nodeIndex = 1,
                i,
                j,
                char;

            xpath = xpath.substr("/html/".length);

            for (i = 0; i < xpath.length; i++) {
                char = xpath.charAt(i);

                if (chunk === "") {
                    if (!element) {
                        return null;
                    }
                    element = element.firstElementChild;
                }

                if (char === "/" || i === xpath.length - 1) {
                    j = 1;
                    if (i === xpath.length - 1) {
                        chunk += char;
                    }
                    chunk = chunk.toUpperCase();
                    do {
                        if (element.nodeName === chunk) {
                            if (nodeIndex === j) {
                                break;
                            }
                            j++;
                        }
                    } while (element = element.nextElementSibling);
                    nodeIndex = 1;
                    chunk = "";
                } else if (char === "[") {
                    nodeIndex = "";
                } else if (char === "]") {
                    nodeIndex = parseInt(nodeIndex, 10);
                } else if (typeof nodeIndex === "string") {
                    nodeIndex += char;
                } else {
                    chunk += char;
                }
            }

            return element;
        }

        function useQuerySelector(xpath) {
            var cssSelector = "",
                i,
                char;

            xpath = xpath.substr("/html/".length);

            for (i = 0; i < xpath.length; i++) {
                char = xpath.charAt(i);

                if (char === "/") {
                    cssSelector += ">";
                } else if (char === "[") {
                    cssSelector += ":nth-of-type(";
                } else if (char === "]") {
                    cssSelector += ")";
                } else {
                    cssSelector += char;
                }
            }

            return document.querySelector(cssSelector);
        }
function useCssSelector(css) {
return document.querySelectorAll(css);
}
function useNativeSelectors() {
return document.getElementsByTagName('body')[0].getElementsByTagName('div')[2].getElementsByTagName('ul')[0].getElementsByTagName('li')[2]
}
function useNativeSelector() {
return document.getElementsByTagName('div')[2].getElementsByTagName('li')[2];
};
function useDynamicString(arr) { var i=0,j=arr.length,call='document';while(i<j){ if(arr[i][0].slice(0,1)=="#"){call+='.getElementById("'+arr[i][0].slice(1,arr[i][0].length)+'")'}else if(arr[i][0].slice(0,1)=="."){call+='.getElementsByClassName("'+arr[i][0].slice(1,arr[i][0].length)+'")['+arr[i][1]+']'}else{call+='.getElementsByTagName("'+arr[i][0]+'")['+arr[i][1]+']'};i++ };return (0,eval)(call) };
function useDynamicDirectCalls(arr) { var i=0,j=arr.length,temp=document;while(i<j){ if(arr[i][0].slice(0,1)=="#"){temp=temp.getElementById(arr[i][0].slice(1,arr[i][0].length))}else if(arr[i][0].slice(0,1)=="."){temp=temp.getElementsByClassName(arr[i][0].slice(1,arr[i][0].length))[arr[i][1]]}else{temp=temp.getElementsByTagName(arr[i][0])[arr[i][1]]};i++ };return temp; };
console.log('Query sel: ',useQuerySelector("/html/body/div[2]/ul/li[3]"));
console.log('Dom trav: ',useDomTraversal("/html/body/div[2]/ul/li[3]"));
console.log('qSA css: ',useCssSelector('div:nth-of-type(2)>ul>li:nth-of-type(3)'));
console.log('Native multi: ',useNativeSelectors());
console.log('Native single: ',useNativeSelector());
console.log('Native dynamic string: ',useDynamicString([['div',2],['li',2]]));
console.log('Native dynamic direct calls: ',useDynamicDirectCalls([['div',2],['li',2]]));
</script>
</body></html>

Test runner

Ready to run.

Testing in
TestOps/sec
query selector
useQuerySelector("/html/body/div[2]/ul/li[3]");
ready
dom traversal
useDomTraversal("/html/body/div[2]/ul/li[3]");
ready
qSA css selector
useCssSelector('div:nth-of-type(2)>ul>li:nth-of-type(3)');
ready
Native JS with all selectors in chain
useNativeSelectors();
ready
Native JS with only the 2 needed elem selectors
useNativeSelector();
ready
Native JS dynamic String
useDynamicString([['div',2],['li',2]])
ready
Native JS dynamic Direct Calls
useDynamicDirectCalls([['div',2],['li',2]])
ready

Revisions

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