For my part, I disagree that using an event per node is The Right Thing (tm) if we want to enable selector matching. EventEmitter is an implementation detail of the API. It is doing tag bucketing for us, but in doing so it divides the selector logic into two separate places, increasing the overall complexity of the implementation. This feels like an optimization in advance of measuring, which I've been bitten by repeatedly in the past (no matter how common sense the optimization seemed at the time!) :) 

The other downside is that the optimization "wears off" if folks start using the selector language feature more (vs. simple tag types).

I agree that calling selectors on each node is a prime candidate for optimization, but I feel we should do so by using a more appropriate data structure around the selector -> rule mapping -- possibly one that divides the selectors into a tree of dependent selectors. Again, I'd prefer we measure first to see if it's the primary bottleneck before going down this route.

-------

In summary: I think my next step should be to get some benchmarks for common workloads into master, and then to implement your proposed solution (EventEmitter + cssauron) alongside this solution and see if there's a large speedup -- and then compare the relative complexity of the two solutions directly with some better metrics around how fast they are. It might also be worthwhile to artificially complicate some percentage of the existing selectors and see how the EventEmitter optimization holds up in that case. Do you have any suggestions for what files might represent typical workloads (ideally one small, medium, and large)?