Side navigation
#1706 closed enhancement (fixed)
Opened September 21, 2007 01:21PM UTC
Closed January 18, 2009 04:10AM UTC
Last modified March 15, 2012 12:28AM UTC
Query by "id" - performance improvement
Reported by: | bonzooznob | Owned by: | brandon |
---|---|---|---|
Priority: | minor | Milestone: | 1.2.2 |
Component: | core | Version: | 1.2.1 |
Keywords: | Cc: | ||
Blocked by: | Blocking: |
Description
When jQuery is looking for an element by the "id" attribute, it uses the browsers native document.getElementById() method, as it is extremely fast.
However due to a bug in IE (also mimicked in Opera), elements with a name attribute matching the id, that appear above the true element (matching the id) in the DOM are returned.
jQuery catches this already, and does a check to see if the (tmp.id != id) if the element is a bogus match (e.g. due to the bug), it then does AFAIK, a 'deep' query checking all elements for a match on the id attribute.
If this is so, then there is a potentially huge performance increase, by implementing the following.
Rather than do the deep query, execute a one-time fix for IE & Opera, to correctly return the first element matching by ID.
IE has a proprietary array on the document called "all", under normal circumstances I would never suggest using it, but in this scenario it is helpful. For every element added to the DOM, with an "id" or a "name", IE adds a named reference to the document.all associative array.
This means, that if you had say, a meta tag, with name="description" and a form element, with id="description" that document.all['description'] would be an array with [meta element, form element]. Since IE has these references cached, pulling them from this dataset is VERY FAST.
The following code would likely need to be re-jigged to match the jQuery format, but essentially this works, by re-mapping the method, to return the correct thing.
//fix both IE and Opera (adjust when they implement this method properly) if(jQuery.browser.msie||jQuery.browser.opera){ document.nativeGetElementById = document.getElementById; //redefine it! document.getElementById = function(id){ var elem = document.nativeGetElementById(id); if(elem){ //verify it is a valid match! if(elem.id == id){ //valid match! return elem; } else { //not a valid match! //the non-standard, document.all array has keys //for all name'd, and id'd elements, and querying //it is FAST! //start at one, because we know the first match, is wrong! for(var i=1;i<document.all[id].length;i++){ if(document.all[id][i].id == id){ return document.all[id][i]; } } } } return null; }; }
Nice idea/solution. I've gone ahead and created patch and uses your idea but more integrated into the core. Of course it adds some bytes but the performance might be worth it in large DOMs where this corner case is encountered.