DOM Efficiency

Twinkie

Banned
Messages
1,389
Reaction score
12
Points
0
I would like to know if there is a more efficient way to do this than I have come up with. I want the last id attribute of a bunch of child nodes, but I can't just get it because of random text nodes just from my html formatting. Having to check node type every time if just not efficient, especially in a heavily dom driven application, so what might be a better solution?

Code:
var divs = document.getElementById('announcements').childNodes;
var i = 0, last_id = false;
do {
    last_id = divs[divs.length - (1 + i)];
    i++;
}
while (last_id.nodeType != 1);
last_id = last_id.id;
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
document.getElementById('announcements').getElementsByTagName('*'); should get all descendent elements, though this will only work for your purposes if the last child of #announcements doesn't have any element children of its own. It will also be less efficient than scanning through the child elements yourself, since getElementsByTagName must itself scan through descendents (though it's a built-in function rather than an interpreted one, so it might be faster). On some browsers, you can use lastElementChild.

Your code isn't likely to be inefficient unless you've appended numerous text nodes through DOM methods. The rest of the time there should be a single text node (or, if there's a comment, two text nodes and a comment node) to go through before reaching an element node. One potential problem with your code is that it assumes the parent node has an element child. This might always be true for your #announcements, but handling the case when the parent has no element children will produce more robust code.

divs.length-1-i is unnecessarily verbose for indexing. You can use i with a few, minor alterations (initialize i to divs.length-1 and decrement it with each loop).

Code:
var divs = document.getElementById('announcements').childNodes,
    i, last_id;
for (i = divs.length-1; i >=0; --i) {
    if (divs[i].nodeType == 1) {
      last_id = divs[i].id;
      break;
    }
}
To find the last ID, you're finding the last element child (the same as the lastElementChild property does), so you might as well factor that out into a function. You can also make use of Node.lastChild and Node.previousSibling.

Code:
var lastElementChild;
if (lastElementChild in document.body) {
  lastElementChild = function (node) {
    return node.lastElementChild;
  }
} else {
  lastElementChild = function (node) {
    var child = node.lastChild;
    while (child) {
      if (child.nodeType == 1) { return child; }
      child = child.previousSibling;
    }
  }
}

...
  var last_elt = lastElementChild(document.getElementById('announcements')),
      last_id;
  if (last_elt) {last_id = last_elt.id;}
Add in cross-browser getters/setters (such as antimatter15 experiments with) and you can have lastElementChild, even when not supported natively.
 
Top