Thoughts on querySelectorAll


I don’t think there’s a single JavaScript developer who isn’t excited about the new Selectors API specification (and the upcoming implementations). I’ve been following the progress of the specification (and implementations) and have been asked to provide some feedback to the Web API working group. What follows is an email that I sent to the public-webapi mailing list.


I just wanted to quickly pull together some of my thoughts concerning querySelectorAll. I’ve been asked by a number of people to provide my feedback here. Please forgive me if I’ve missed some previous discussions on the subject matter.

There’s three major points that I wanted to discuss:

DOMElement.querySelectorAll returning incorrect elements

This is the most critical issue. As it stands DOM Element-rooted queries are borderline useless to libraries – and users. Their default behavior is unexpected and confusing. Demonstrated with an example, using Dojo:

  1. <div><p id="foo"><span></span></p></div>
  2.   <script src="http://o.aolcdn.com/dojo/1.1.0/dojo/dojo.xd.js"></script>
  3.   <script>
  4.   var foo = document.getElementById("foo");
  5.   // should return nothing
  6.   alert( dojo.query('div span', foo).length );
  7.   // will return the SPAN (booo!)
  8.   alert( foo.querySelectorAll('div span').length );
  9.   </script>

The demo can be run online here:
http://ejohn.org/files/bugs/qsa-root/dojo.html

This is due to the fact that element-rooted queries are handled by “finding all the elements that match the given selector — rooted in the document — then filtering by the ones that have the specified element as an ancestor.” This is completely unacceptable. Not only is it not intuitive (finding elements that don’t match the correct expression) but it goes against what every single JavaScript library provides. If there behavior were persisted then there would be serious ramifications for the usefulness of this function in the wild.

I asked some of the other library developers what their thoughts were and they agreed with my conclusion.

Andrew Dupont (creator of Prototype’s selector engine):

My issue with this is that it violates principle of least surprise and bears no resemblance to the APIs in the wild.

Alex Russell (creator of Dojo’s selector engine):

This is a spec bug.

Combinator-rooted Queries

I read about some prior discussion concerning this (especially in relation to DOMElement.querySelectorAll-style queries). This is an important part of most libraries, as it stands. Maciej’s proposed solution of using :root to allow for front-leading combinators is perfectly acceptable to me (where :root is made equivalent to the element, not the document element).

  1. // jQuery
  2.   $("#foo").find("> span");
  3.  
  4.   // DOM
  5.   document.getElementById("foo").querySelectorAll(":root > span")

This is something that a library can easily detect and inject.

Error-handling

I’m perfectly fine with the proposed try/catch solution however there must be a way of easily determining what the invalid portion of the selector was. Currently the following occurs in Safari:

  1. try {
  2.     document.querySelectorAll("div:foo");
  3.   } catch(e) {
  4.     alert(e); // "Error: SYNTAX_ERR: DOM Exception 12"
  5.   }

If there were extra properties to point to what the inappropriate selector was, that’d be fundamentally important. Probably the best solution (for both implementors and JavaScript library authors) would be to simply provide a character index, working something like the following:

  1. var selector = "div:foo";
  2.   try {
  3.     document.querySelectorAll(selector);
  4.   } catch(e) {
  5.     alert(selector.slice(e.position)); // ":foo"
  6.   }

The resulting solution in most libraries would then look something like (of course different caching could take place, as well):

  1. try {
  2.     results = document.querySelectorAll(selector);
  3.   } catch(e) {
  4.     results = filterQuery(
  5.       document.querySelectorAll( selector.slice(0, e.position) ),
  6.       selector.slice(e.position)
  7.     );
  8.   }

There will be some form of a performance hit here but I think, if done correctly, it’ll be negligible (especially in comparison to the benefits that are being received).

I hope these proposed changes work well for the members of this group as they will greatly benefit general web developers – and especially library developers.

Posted: April 30th, 2008


If you particularly enjoy my work, I appreciate donations given with Gittip.

15 Comments (Show Comments)



Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question concerning the content of this post, please feel free to contact me.


Secrets of the JavaScript Ninja

Secrets of the JS Ninja

Secret techniques of top JavaScript programmers. Published by Manning.

Ukiyo-e Database and Search

Ukiyo-e.org

Japanese woodblock print database and search engine.


John Resig Twitter Updates

@jeresig

Infrequent, short, updates and links.


via Ad Packs