patternjavascriptMinor
Very fast query selector
Viewed 0 times
fastqueryselectorvery
Problem
A few months ago, I wrote a query selector that seems to outperform the query selectors in the popular GP libraries by a pretty hefty margin. I'm wondering if I overlooked something. It seems odd that with all the manpower behind these other projects. It's this easy to come up with something that outperforms them.
The "trick" behind it is instead of parsing the query string every time, it will cache each query as a series of commands ("command pattern") to avoid parsing it again. Note that the results aren't cached, just the series of commands to be performed to get the results.
There are also some minor optimizations. For example, I assume that there isn't more than one
This supports CSS1 only (tag name, class name, id), but I think adding features from later CSS-es shouldn't affect the performance of the current code much at all, thanks to the "command-caching" design.
Have I overlooked something important? Is this fast because it's failing to do something critical? Is there something inherently wrong with this design, or is it possible the GP library authors have simply not considered this sort of design?
```
/**
A simple, fast query selector.
@fileOverview
*/
/**
Perform a simple query selection.
@param {String} query
@param {Node} root
Optional root node, defaults to qs.global.document.
@returns {Array|NodeList}
DOM nodes matching the query.
@namespace The root qs namespace.
*/
function qs(query, root) {
var doc = root ? root.ownerDocument || root :
(root = qs.global.document);
return qs.run(qs.cache[query] || qs.compile(query), {
root: root,
doc: doc
}).nodes;
}
/**
A reference to the global object.
@type Object
*/
qs.global = (function () {
return this || [eval]0;
}());
/**
Holds command arrays, keyed by query string.
@type Object
*/
qs.cache = {};
/**
Various regexen.
@type Object
@private
*/
qs.rx = {
singletons: /^(?:body|head|title)$/i
The "trick" behind it is instead of parsing the query string every time, it will cache each query as a series of commands ("command pattern") to avoid parsing it again. Note that the results aren't cached, just the series of commands to be performed to get the results.
There are also some minor optimizations. For example, I assume that there isn't more than one
head, title, or body tag in the document.This supports CSS1 only (tag name, class name, id), but I think adding features from later CSS-es shouldn't affect the performance of the current code much at all, thanks to the "command-caching" design.
Have I overlooked something important? Is this fast because it's failing to do something critical? Is there something inherently wrong with this design, or is it possible the GP library authors have simply not considered this sort of design?
```
/**
A simple, fast query selector.
@fileOverview
*/
/**
Perform a simple query selection.
@param {String} query
@param {Node} root
Optional root node, defaults to qs.global.document.
@returns {Array|NodeList}
DOM nodes matching the query.
@namespace The root qs namespace.
*/
function qs(query, root) {
var doc = root ? root.ownerDocument || root :
(root = qs.global.document);
return qs.run(qs.cache[query] || qs.compile(query), {
root: root,
doc: doc
}).nodes;
}
/**
A reference to the global object.
@type Object
*/
qs.global = (function () {
return this || [eval]0;
}());
/**
Holds command arrays, keyed by query string.
@type Object
*/
qs.cache = {};
/**
Various regexen.
@type Object
@private
*/
qs.rx = {
singletons: /^(?:body|head|title)$/i
Solution
My 2 cents,
for my edification
* why
As far as I can tell, your library is fast because you optimized for the test case. You ought to generate a DOM structure with a thousand elements and query each one ( rendering your cache useless ), will your library still be faster? Most JavaScript authors cache the lookups for efficiency and will not repeat queries unless the DOM changed.
- Well commented
- Naming is never confusing
- Quite readable
for my edification
* why
[eval]0 instead of eval('this'), to trick lint?As far as I can tell, your library is fast because you optimized for the test case. You ought to generate a DOM structure with a thousand elements and query each one ( rendering your cache useless ), will your library still be faster? Most JavaScript authors cache the lookups for efficiency and will not repeat queries unless the DOM changed.
Context
StackExchange Code Review Q#25452, answer score: 5
Revisions (0)
No revisions yet.