Why doesn't querySelector('#id') map to document.getElementById('id')?
Asked Answered
H

4

10

I'm into selectors performance lately, and it's bugging me that the browsers which currently implements the Selectors API don't use document.getElementById when a simple #id is being passed.

The performance penalty is huge, so library authors continue to implement their own way around that.

Any ideas?

Herman answered 28/11, 2010 at 19:13 Comment(8)
I haven't looked at the source to those browsers, but are you sure they don't map directly? There is going to be a performance penalty for parsing the string and working out if it is just a straight id.Jansen
Guys if you click through to that jsperf test linked in the question, it should be clear that if the browser is trying to shunt a '#id' selector into getElementById() resolution, it's doing a terrible job of it. It's probably not trying.Monopolist
Ok, here’s some evidence: WebKit does map querySelector onto document.getElementByIdTriparted
@Triparted — OK, now I have to delete my answer that quoted that section of the code!Jansen
@David Dorward: Why? It’s you that gave the answer for why the difference is that “huge”.Triparted
@Triparted — I didn't think the comment about string parsing being expensive was that significant, but if you disagree then I'm happy to put the answer back.Jansen
@David Dorward: It’s not just the parsing but also the additional check whether the element with that ID is also a descendant of the node that querySelector was called on.Triparted
Thank you both, guys :-) This is the best answer I could have asked for.Herman
J
12

After making my comment above, I decided to follow through:

From Node.cpp in the Chromium source

if (strictParsing && inDocument() && querySelectorList.hasOneSelector() && querySelectorList.first()->m_match == CSSSelector::Id) {
    Element* element = document()->getElementById(querySelectorList.first()->m_value);
    if (element && (isDocumentNode() || element->isDescendantOf(this)) && selectorChecker.checkSelector(querySelectorList.first(), element))
        return element;
    return 0;
}

So it does map on getElementById, it is just that parsing the string looking for selectors is an expensive operation.

Jansen answered 28/11, 2010 at 19:30 Comment(1)
Thanks, David! I Didn't know where to look at in Chromium's source.Herman
S
3

Tbh. the performance penalty is insignificant... I really doubt you're going to do 100.000 id lookups per second, if you do, then QSA performance is actually the last thing you should look at.

As to why, adding an extra if/else might make id lookups more performant, but then other css selectors will be a fraction (still insignificant) slower. Why optimize QSA to deal with id lookups when there's a specialist method to do exactly that a lot faster anyways.

In any case, browsers are aiming for speed and leaving out stuff like this makes the overall performance charts look a lot better. In this benchmark race it's REALLY about every single millisecond, but for the developers... please be realistic, other benchmarks are more important, QSA performance shouldn't really be a factor anymore.

As for developer convenience, it works, it's still so fast you won't notice it in actual applications (I challenge you to show me where it's IS VISUALLY noticable whilst still being a sane program ;o).

Sanguinaria answered 28/11, 2010 at 19:31 Comment(0)
R
0

Maybe because if they did that, they would have to add a check to see if its a simple id query (no modifiers) which would slow down every other query? It might not be a huge performance hit to do the test, but its difficult to speak for other developers.

I think if you are worried about it you can add a func like getObByID that checks for document,getElementById, uses it if it exists, else uses the selector. Maybe the developers don't feel the need to add this type of abstraction when you can easily do it yourself, and it would be up to developers to remember to use it, and increase learning curve.

Retroact answered 28/11, 2010 at 19:22 Comment(0)
M
0

I was comparing getElementById() and querySelector() and found that someone has already done performance comparisons and calculations.

It certainly looks as though querySelector() wins every time... and by a considerable amount.

Melentha answered 25/6, 2012 at 8:37 Comment(1)
I think you may have it backwards.Ponder

© 2022 - 2024 — McMap. All rights reserved.