Bug Tracker

Opened 12 years ago

Closed 11 years ago

Last modified 8 years ago

#1706 closed enhancement (fixed)

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.alldescription? 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 12 years ago.

Download all attachments as: .zip

Change History (4)

Changed 12 years ago by brandon

Attachment: 1706.diff added

comment:1 Changed 12 years ago by brandon

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.

comment:2 Changed 12 years ago by flesler

Owner: set to brandon

comment:4 Changed 11 years ago by dmethvin

Resolution: fixed
Status: newclosed

Added in jQuery 1.3

Note: See TracTickets for help on using tickets.