Skip to content


Subversion checkout URL

You can clone with
Download ZIP


querySelectorAll is Often Surprisingly Slow #4

paulirish opened this Issue · 9 comments

6 participants


In many cases, querySelectorAll is slower than the counterpart DOM method for simple selectors. For instance, querySelectorAll(‘tagName’) is slower than getElementsByTagName(‘tagName’).

Specific Issues

  • querySelectorAll is slower than the lower-level DOM methods
    • querySelectorAll(tag) is slower than getElementsByTagName
    • querySelectorAll(class) is slower than getElementsByClassName
    • querySelectorAll(id) is slower than getElementById
  • Action Items:
    • Do benchmarking on all browsers
    • File individual tickets with browser vendors for each instance in which querySelectorAll is slower than the lower-level DOM method
    • Make sure that the same mistake is not repeated with queryScopedSelector
      • Note: Why can we not just fix querySelectorAll? Are there cases where web authors are relying on the non-scoped behavior?
  • External Contact: Browser vendors




Agreed. For reference, here's a jsPerf test that compares qSA vs. getElementsByTagName, getElementsByClassName, getElementById and other alternatives:

If the test is valid, it's curious that it's only really in Opera that we see almost similar levels of performance between the qSA implementation when compared to the others.


Some benchmarks on jQuery & selectors. (sorry for the bad named link)
In my data, querySelector really shines in Opera, just below the simple selectors in everything else.
So, if only the other browser vendors copy what Opera does, this should get fixed easily.


I'm sure many of you have already seen this, but it is worth reposting in this thread:

I am all for fixing querySelectorAll with regard to scope... though deprecating in favor of a better name (see next paragraph) can solve temporary breakage.

And throwing in a +1 for shorter names (if that is something open for debate here too). The w3 list convo mentions primarily human reasons for shortening the names, but I think machine reasons are valid as well... even just switching to queryAll may save hundreds of bytes in a robust web application (assuming we are expecting devs to actually use these commands directly instead of just creating frameworks around them).


It would make sense that QSA all is slower then the relevant native method. Because you have to run a more complex parser on the QSA input.

Yes QSA shouldn't be that much slower, the parser run on QSA input should be optimised however we should not be using QSA for these simple selectors anyway so does it really matter?


@Raynos There should not be a litmus test for whether you should use qSA, that would mean that anyone providing an abstraction would need to codify the litmus test themselves.


@scottgonzalez please clarify what you mean with "litmust test" it appears to be some political term I find hard to apply to the topic.


@Raynos, @addyosmani is correct. I was replying to your comment that "we should not be using QSA for these simple selectors anyway." In many cases the person writing the selector is not the person writing the code that accepts the selector as a parameter. jQuery is a perfect example of this, where any selector can be passed, but jQuery has to make decisions about how to query for those elements based on what the selector looks like. Surely qSA can do those checks at least as fast as a JavaScript implementation can.


If it is simply that certain browsers are off by a significant amount (in terms of perf), then we just need those browsers to catch up. If it is more generic than that, it is likely due to the static NodeLists (more so than the extra selector parsing).

Obviously we cannot change querySelectorAll to sometimes use dynamic vs static NodeLists; that would make for a chaotic api. We may have to either go the route of changing querySelectorAll (or new named func) to always return a dynamic NodeList in order to match speed on these simple queries. Or we may want to continue to have QSA return a static NodeList and eat the small perf difference on initial query.

Is there any good documentation as to why QSA was decided to use static NodeLists?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.