Boris Zbarsky wrote:
On 9/24/09 6:45 PM, Sean Hogan wrote:
That is surprising. Does the CSS engine do the same? If the CSS engine
doesn't store the parsed selector then it probably doesn't matter for JS
calls either.
In Gecko the CSS engine stores the parsed selector. In addition, it
stores the selectors in various bins in a data structure to make
matching faster. In practice this means that you don't have to
actually match most nodes against most selectors when computing the
set of rules that match a given node. This makes sense because you're
guaranteed that every time a node is inserted into the DOM you will
have to match it against every single one of those selectors.
https://developer.mozilla.org/en/Writing_Efficient_CSS has a
description of the setup. I believe Webkit has something similar.
Again, I can't speak to Trident or Presto.
In the querySelector(All) case, the browser has no way to know that
the selector will ever be reused. In practice, the native
implementations were enough faster than what they were replacing, even
without any particularly fancy optimizations, that simplicity was
judged more important than squeezing every bit of performance out. At
least in Gecko's case. If we get to the point where they're being a
bottleneck again, that will likely be revisited.
Take a event-delegation system that uses matchesSelector.
Every event that it handles will walk the event path trying
element.matchesSelector with every registered handler.
e.g. There are twenty registered click handlers and a click event occurs
on an element ten levels deep. There could be 20 * 10 = 200 calls to
matchesSelector. Or 400 if the system simulates capture phase as well.
200 calls would equate to ~1ms of selector parsing time in the the
case of Gecko. For a click event, that's not terrible.
No. It will be negligible compared to everything else that has to be done.
Or take a framework that adds enhancements to HTML elements based on
selectors.
The framework wants to handle dynamic insertion to / removal from the
page, so every DOMNodeInserted / DOMNodeRemoved (or equivalent) it will
call querySelectorAll for all registered enhancements to see if there is
any work to do.
This could be much more of a problem. I'd want be interested in what
the actual performance is like in this situation. Remember, the
selector-parsing time was just the overhead; the real time usage is
walking the DOM and doing the matching. For matchesSelector this is
much less significant, of course, but for querySelectorAll it's likely
to be the dominating factor (gut feeling; if someone wants to measure
that would be welcome).
I also wonder how well XBL or something like that would handle cases
like this... This setup (matching every node in a subtree against a
set of selectors) is really not that well served by any of the APIs
described here. It's much closer to the CSS use case and would
benefit from similar optimizations.
XBL (and standard DOM implementations) is what we want.
Note that I don't have anything against exposing "parsed selector"
objects in JS. I don't think it would be that difficult to implement
it. I'm just not sure whether the added complexity is really needed,
and whether it's the best solution for the use cases. Maybe it is;
I'm just gathering data. This is not exactly my area of expertise.
-Boris
Thanks for that perspective. My main concern was that we don't create
parsed selectors in JS (at least not for performance reasons).