Permalink
Browse files

Replace Prototype's Selector implementation with Sizzle

  • Loading branch information...
1 parent 9e4a7ce commit 4dd878f237e79db11a6532e3f74059c9b908069c @sstephenson committed Sep 19, 2009
Showing with 24 additions and 798 deletions.
  1. +3 −0 .gitmodules
  2. +2 −1 Rakefile
  3. +18 −789 src/dom/selector.js
  4. +0 −8 test/unit/selector_test.js
  5. +1 −0 vendor/sizzle
View
@@ -11,3 +11,6 @@
path = vendor/sprockets
url = git://github.com/sstephenson/sprockets.git
+[submodule "vendor/sizzle"]
+ path = vendor/sizzle
+ url = git://github.com/jeresig/sizzle.git
View
@@ -9,6 +9,7 @@ module PrototypeHelper
DOC_DIR = File.join(ROOT_DIR, 'doc')
TEMPLATES_DIR = File.join(ROOT_DIR, 'templates')
PKG_DIR = File.join(ROOT_DIR, 'pkg')
+ SIZZLE_DIR = File.join(ROOT_DIR, 'vendor', 'sizzle')
TEST_DIR = File.join(ROOT_DIR, 'test')
TEST_UNIT_DIR = File.join(TEST_DIR, 'unit')
TMP_DIR = File.join(TEST_UNIT_DIR, 'tmp')
@@ -18,7 +19,7 @@ module PrototypeHelper
require_sprockets
secretary = Sprockets::Secretary.new(
:root => File.join(ROOT_DIR, path),
- :load_path => [SRC_DIR],
+ :load_path => [SRC_DIR, SIZZLE_DIR],
:source_files => [source],
:strip_comments => strip_comments
)
Oops, something went wrong.

16 comments on commit 4dd878f

nel replied Oct 3, 2009

Does it feel good to get rid of this ?

Sizzle implementation is not only efficient at replacing $$, it is also particularly efficient at matching ancestors element against a css selector. It makes it a breath to use for event delegation. By replacing old implementation of Selector.findElements() by Sizzle.matches() you increase performance of event delegation by an order of magnitude on Firefox and particularly IE

Very happy to see this coming on prototype, thank you!

Collaborator

kangax replied Oct 5, 2009

Strange. I always thought Sizzle uses top-down, not bottom-up selector engine.

nel replied Oct 5, 2009

Actually it depends of the selector, but Sizzle.matches (which is a replacement for Selector.findElements) actually search bottom-up in most real case (i.e. not nth-child and stuff like that).

Look at sizzle.js L66-96, it does pop() the selector chunk backward. If you have a query like $('foo').up('.class1 .class2') what it does is:

- Fetch foo.ancestors (it is still real prototype extended Element which is not needed but it's ok for now)
- Search for class2Elt = element matching '.class2' selector in foo.ancestors() (quick match on the className)
- Search for parentNode of class2Elt that match '.class1' (still very quick)
- return class2Elt if it is success or nothing otherwise

It cannot be quicker in that particular case, and that particular case is 99% of the event delegation case.

Prototype previous was Searching all elements matching $$('.class1 .class2') (which lead to 2 huge intersection) and then Intersect with ancestors() which was awfully slow in case of frequent event like mouseout, mousemove ...

Collaborator

kangax replied Oct 5, 2009

@jdalton It is a shame. I brought it up few times, but no one seemed to be interested (I think an argument was that Sizzle is more popular and doesn't compile functions - so is compatible with Caja).

nel replied Oct 6, 2009

$$ search pattern is just a tiny part of the selector problem. A part which will become more and more irrelevant given native QSA will soon be the norm. .up(expr) .next(expr) and related methods are the limiting methods but no one is publishing any bench on those, results would probably be surprising and not kind to current Prototype master.

Sizzle is currently good enough at them, NWMatcher probably too but we have to be more careful given its compiled nature to see if it fits real world use (i.e. short lived Element instance anywhere traversing the dom in many direction with many selector).

Whatever the choice is, Prototype current implementation could support several adapter, so we are not stuck to Sizzle. IMHO the important step is to go forward and get rid of the current engine to get decent performance without crazy caching.

Contributor

jdalton replied Oct 6, 2009

@nel - early alpha benchmarks of a work in progress framework using NWMatcher http://twitter.com/fusejs/status/3166496154. NWMatcher also passes the unit tests of Prototype and jQuery.

Contributor

jdalton replied Oct 6, 2009

@nel also it's not "crazy" caching it's "intelligent" caching :D

Contributor

gf3 replied Oct 6, 2009

I was secretly hoping for NWMatcher as well, but Sizzle is still a vast improvement over Selector.

Contributor

samleb replied Oct 9, 2009

NWMatcher is blazing fast, and it's a robust and complete selector implementation.
We just cannot ship as part of framework because function compilation at runtime isn't compatible with Caja (we're already trying to get rid of all eval calls).
As @nel pointed out, what's important for Prototype is to have a selector adapter API so any implementation could be plugged in depending on your needs (application with lot of event delegation vs. embeddable widget with security considerations).
This is planned for future releases.

Collaborator

savetheclocktower replied Oct 10, 2009

I could not have said it better myself.

First of all thanks to all the NWMatcher supporters here and to the team for its consideration !

At many selectors your current engine is faster than Sizzle, some other selectors are incredibly slow though.
I have even thought about not being the Selector engine by itself the real slow down in those specific ones but wrappers and prototyping overhead and extending elements. I say this because I have the numbers of the few tests around under my eyes everyday.

The point should be moved to have a real matcher in Prototype one that can be used as a fall back to the already implemented webkit and moz MatchesSelector(), the priority is not changing the selector engine, having a matcher will automatically let you improve your current selector engine.

I say this knowing that NWMatcher will not be considered for the above reasons: Caja new Function() blah blah, I am trying hard to convince them this is so useful they can't just forget/ignore it. An alternative should be available this is just pure ECMAScript code it's not a virus !

Still, what you need in Prototype is a matcher, so see what are the alternatives, the adapter one seems good for me too. Hope this helps !

PS: we have now the very first tests of the match() method running vs. original browsers implementations so you may have a peek here:

http://dl.getdropbox.com/u/598365/matchspeed/matchspeed-custom.html

as a bonus I recently added a "data" parameter and "callback" capabilities to the engine, you will love these additions...promised... ;-)

Collaborator

tobie replied Oct 22, 2009

@kangax: I've been following NWMatcher since it's inception and I know it's merits. As Andrew and Samuel both mentioned above, we're all very keen to make Prototype selector agnostic in the near future. That being said, Sizzle seems like a good default options for the various reasons already discussed (popularity, Caja compliance, etc.).

@diego: Im totally with you on the Selector / Matcher distinction. I wasn't aware that there was a matcher implemented in WebKit and Firefox. What is the API like? Where can I find some info on it? It would be great to have a common API for all selector engines so that switching engine could be a drop-in or evan a runtime replacement.

Collaborator

kangax replied Oct 22, 2009

@tobie,
the API are quite simple and in-line with how my match() method work. I also already submitted a ticket to Webkit asking them to improve speed ;-)

I am so happy they introduced those, this is like a reward for me and my work. I can finally test things Vs. native implementations and be able to show.
I did some more test on combinators and className resolution and seems Prototype is faster or at least on par with other selector engines on those.

Is Prototype using XPATH to resolve classNames internally ?
I know XPATH being very fast for those expensive operations...but it is not available everywhere though.

An adapter will be very easy for NWMatcher, both for the select() and match() methods, and you may opt to only adopt the match() method. The work Samuel did in my NWMatcher to make the unit tests work was already an attempt to this, the remaining parts are probably in Juriy "traversal" API he adapted for NWMatcher (up/down/next/prev).

Let me know if I can be of help in this process, I would love too see my NWMatcher used intensively, even if it has to be trough an adapter.

Please sign in to comment.