Skip to main content

Bug Tracker

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;
  };
}
Attachments (1)
  • 1706.diff (1.1 KB) - added by brandon November 14, 2007 03:52AM UTC.
Change History (3)

Changed November 14, 2007 03:54AM UTC by brandon comment:1

need: ReviewCommit

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.

Changed May 12, 2008 01:10AM UTC by flesler comment:2

owner: → brandon

Changed January 18, 2009 04:10AM UTC by dmethvin comment:3

resolution: → fixed
status: newclosed

Added in jQuery 1.3