Tuesday, September 28, 2010

jQuery,Ext custom css selectors: avoid the framework war

In the last entry, we saw how javascript frameworks compare when using css3 standard selector queries. Now, we will see how those frameworks compare when using custom css selectors,ie,not W3 standard selectors. jQuery is well known for implementing very nice shortcuts like ":input", ":radio" or ":even",":odd". We will see how these shortcuts are handled and see that you should avoid them when possible and stay away from the framework war...

Test using jsslickspeed

jsslickspeed is a fork of slickspeed containing both standard selectors and custom selectors tests + document.querySelectorAll when available.

Read the result for the standard selectors

Same frameworks, same browsers tested.
We will look into the custom css selectors test in this entry. You can run the test yourself.

CSS3 custom selectors result

It is not necessary to go through each browser results to say that frameworks custom implementation slows down from little to greatly the speed of the test.

You can find all the result charts at the end of this article but let's sum up...
  • Custom selectors not handled by libraries does not throw any error
Obviously, not all libraries implement the same selectors...
most of them implement the attribute negation look up "!=", the pseudo-class ":contains" and some of them ":even" and ":odd".
This basically means that we enter in a non-standard world where the selectors you were using with one framework may not work, even worse, send back results instead of throwing an error.
Well, if you are a jQuery guru, an ExtJS guru, using each framework custom selectors within one project is not going to be harmful but you may need to switch of javascript framework for your new job and you will have to learn anew what you can use and what you can not use. If you force yourself to use standard selectors, this problem will not occur.
  • Native standard selectors are most of the time faster than the custom ones 
some concrete examples:

jQuery ":parent" tooks 8ms against 1ms for ":not(:empty)"  in Firefox 3.6...

jQuery "div > *:input" took 115ms against 4ms for its counter part (i have to say that the native one is very long: div > input,div > select,div > textarea,div > button) in IE6

jQuery ":submit" tooks 20 ms against 1ms for "[type=submit]" in Firefox even though the doc seems to specify cross-browser issue being handled...

":odd" and ":even" takes about 13ms against 3ms for ":nth-child(even|odd)" for jQuery while Ext JS which implements these shortcuts too took a constant time. READ BELOW FOR A POSSIBLE REASON
  • Custom shortcuts are not implemented the same way...
It seems like we are in the "browser war" again where each framework wants to implement its extra feature to make the difference...because it sounds better this way...
This get tricky though.
jQuery implements :even and :odd has a shortcut for nth-child(even) and nth-child(odd) with the difference that it is a 0 based indexed whereas the W3 standard states a 1 indexed based calculation.
But well, it could be ok if...
  • Shortcuts may not work properly
jQuery returned exactly the same result for both :even and :odd...

Looking at the result you will see the library returns the exact same number for those two selectors...so : div > p:even == div > p:odd. Both of them different from div >p:nth-child(even) and div > p:nth-child(odd)...
Ext also implements the :even and :odd shortcuts but does follow the W3 standard declaration and use an index starting from 1. It does send back two different results for :even and :odd and these results do match there standard counterparts, nth-child(odd|even).
  • Custom selectors... are not interoperable
Yes, like the old time,with browsers implementing their own javascript APIs because it seemed great at the time. This left us with an horrifying war-land where no browser could be trusted...
ok, I am a little bit dramatic here but come to think of it...
If browsers decide to implement :even,:odd or :input but that they use for the first ones, the standard definition starting from 1? Libraries will have to resort to their own implementation in order to keep older applications running,eventually, slowing down the entire process. If :input is implemented but only send back input tag fields? The same here...

Being a good citizen and avoid the framework war

All these shortcuts/customs selectors, not available by default are very useful and tempting but...
Obviously when you use a shortcut or a custom selector, libraries will have to use their own engine instead of using the native selector when available.

What does it mean?
  •   It will be slower most of the time. You loose the speed of the native selector.
  •  You loose the checking done by the native selector who has a real low level lexer(most of the libraries will silently return something instead of throwing an error when you write an unsupported selector) 
  • Uncoherent implementation between frameworks is at best confusing at worst could lead to problem if the browser implements themselves these shortcuts. (let's say :even and :odd is implemented and are equal to nth-child(odd|even)... some libraries will have to resort to their own engine for compatibility issues and you will loose all the benefit of the native selector implementation).
As a result and for better interoperability you should use as much as possible the standard selectors.

If you can use a standard selector in lieu of a custom selector, please do so...It will be,well, standard, interoperable and faster for new browser and sometimes even older ones,for example:

:parent use :not(:empty)

:even use nth-child(even)

:odd use nth-child(odd)

:input use input,select,textarea,button
For this one,if it is too long,most of the time your mark up should allow you to target them anyway like #formContainer label *. Obviously it does link your javascript to the underlying html layout which is not ideal...

Below are the results for the custom selectors:

Safari 5 (Win) CSS3 custom selectors IE6 Emulated CSS3 custom selectors IE8 CSS3 custom selectors IE7 CSS3 custom selectors Chrome 6 (Win) CSS3 custom selectors