20

Be specific on the right-hand side of your selector, and less specific on the left.

// unoptimized
$('div.data .gonzalez');

// optimized
$('.data td.gonzalez');

Quote Source

  1. Could someone explain why the less specific left is faster as a CSS selector?

  2. Is this a Sizzle thing or does the same apply for document.querySelectorAll ?

  3. Are there any speed gains using "similarly optimised" CSS selectors in CSS files?

Raynos
  • 166,823
  • 56
  • 351
  • 396
  • I guess this is wrong, not? Selecting a lot from a lot, then a little from this lot is more expensive than selecting a little from a lot then a lot from this little. – ariel May 17 '11 at 09:16
  • 2
    @ariel: Sizzle (the jQuery selector engine) is an interesting beast. Sometimes things that seem obvious on the surface are not actually true. I seem to recall that Sizzle will (for good reason, apparently) sometimes work inside-out -- e.g., first find the `td.gonzalez` and then look to see if it's inside a `.data`. But I suspect like most generalizations, it can be wrong as much as it's right depending on circumstances (how many `div` vs. `td` elements there are, for example). – T.J. Crowder May 17 '11 at 09:21
  • Whether the second version is optimized or not depends very much on your HTML. – Felix Kling May 17 '11 at 09:23
  • 1
    When in doubt, use jsperf.com – Marko Dumic May 17 '11 at 09:28
  • Seems like a pretty fruitless claim. I mean they just say "its better" no tests, no graphs, nothing. Try [this fiddle](http://jsfiddle.net/garreh/W6Phy/) and see there is basically no difference in speed. If you swap the two around you'll see one now beats the other. Maybe there are other selectors that are more complex that would benefit, but in the real world, probably not significant at all. – Gary Green May 17 '11 at 09:29
  • made a perf http://jsperf.com/specific-on-left-or-right-hand-of-jquery-selector -- but it's not showing difference ... if anyone want to improve – ariel May 17 '11 at 09:31
  • 1
    @Gary: It'll vary quite a lot depending on what browser you're using. If you're using a modern browser, it'll have `querySelectorAll` and you probably won't notice any difference as its all internal to the browser's engine. If, though, you're using IE6 or IE7, you'll notice a big difference (in a synthetic test; whether that translates to real-world differences is something else entirely). Try this, for instance, in IE7: http://jsperf.com/specific-left-or-right The more specific right-hand side wins quite handily. But this is all micro-optimization. – T.J. Crowder May 17 '11 at 09:33
  • *(related)* My answer here: http://stackoverflow.com/questions/4699931/jquery-optimization-selector/4699952#4699952 – Felix Kling May 17 '11 at 09:35
  • @ariel: Great minds, I did too. As I said to Gary, it'll depend a *LOT* on what browser you test it with. But this is micro-optimization. Unless there's a real-world problem to solve (a page with an actual, noticeable lag finding something) it's not worth worrying about. – T.J. Crowder May 17 '11 at 09:35
  • @ariel: There is no difference because no matter which selector you use, at each step each one selects the same elements. I would make a difference (theoretically) if you had much more elements with class `s15` that are **not** `span`s. It depends on the actual HTML. – Felix Kling May 17 '11 at 09:36
  • @T.J.Crowder Thanks for pointing out the difference is for old browsers. Maybe make that as an answer. Also note [this perf](http://jsperf.com/specific-on-left-or-right-hand-of-jquery-selector) Showing a 65% speed gain on IE Quirks Mode – Raynos May 17 '11 at 09:37

2 Answers2

7

jQuery's Sizzle Engine parse selectors from right to left, so it's true. There are exceptions though, for example when the first operand is an ID. Then the search will operate in the context of the element with this ID. That's a particularity of the Sizzle Engine, but I don't know how querySelectorForAll is implemented.

An example:

$('div.data .gonzalez');

Sizzle will get all the DOM elements with class gonzalez then check for each if an ancestor is a div tag with class data

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Grooveek
  • 10,046
  • 1
  • 27
  • 37
3

The book sort of mentions this in passing, but I'm fairly certain that advice is specific to Sizzle (the jQuery selector engine), not generally. Your mileage may vary, but a browser that implements querySelectorAll is unlikely to show a real-world difference.

Sizzle works inside-out when appropriate, and so may look for td.gonzales and then look to see if it's within a .data, rather than the other way around. I remember when Sizzle first came out, this was a bit of a surprise, but it actually worked out better. So you can see why the more specific the right-hand side of the descendant selector, the better.

Here's a test case, try that in IE7 and you'll see a marked preference for the more specific right-hand side. But try it in a modern browser and you should seem basically no difference.

This is all micro-optimization, though, and pretty much useless in the absence of a real-world problem to solve, because it varies dramatically based on the elements on your page. Useful to remember if you actually have a slow selector causing you trouble on older browsers, perhaps, but other than that...

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • That book really should mention that Sizzle reads right to left. That was not common knowledge for me. I was aware it's a micro optimisation, it was just difficult to see why it would be faster if it was left to right. It's useful to know how to optimise selectors if I ever need to. – Raynos May 17 '11 at 09:42
  • @Raynos: Well, I'm pretty sure it doesn't *always*. But I think (*think*, mind) that it does for descendant selectors unless it can anchor itself with an ID. – T.J. Crowder May 17 '11 at 09:44