My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Monday, September 21, 2009

One Function To Trap Them All

This is a quick one. This technique could have some side-effect I am not aware about but I've never seen it so far in any library. Talking about LiveMonitor I have successfully tested same concept to create faster implementation of some of my DOM common code, not yet updated in vice-versa.

document.getElementsByClassName Example


(function(childNodes){

/* Another (C) WebReflection Silly Idea */

// how to re-use them all, just an example
if(!document.getElementsByClassName)
document.getElementsByClassName = function getElementsByClassName(className){
for(var
re = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"),
ret = [], i = 0, l = 0, length = childNodes.length, node;
i < length; ++i
){
if((node = childNodes[i]).nodeType === 1 && re.test(node.className))
ret[l++] = node
;
};
return ret;
}
;

// let the magic happen
})(document.getElementsByTagName("*"));

What we have here?
  1. A trapped live object, probably used in 90% of selector libraries, but performed via scope resolution (the document) and a function execution (the getElementsByTagName method) over all nodes ("*")
  2. a theoretically zero performances impact to retrieve again every node, being live there is no need to refresh it, and being trapped run-time, it will contain few nodes during the first execution
  3. a single scope able to create N functions based on one of the most common created HTMLCollection


What do you think?

13 comments:

  1. Nice approach. Cool way to write your for loop also.

    ReplyDelete
  2. I like the thought process here. Good idea.

    ReplyDelete
  3. @fearphage thanks again for the nodeType suggestion (and the silly typo for the className) :D

    Cheers guys

    ReplyDelete
  4. Hey I don't understand the regex

    (?:\\s|^) doesn't that mean you're checking for character before the beg. of the line?

    ReplyDelete
  5. Samer, that means look for a space or it starts with and look for a space after or it ends with.
    The question mark is to avoid RegExp result cache.

    Aaraon, not yet, what I expect is better loop performances, what I need to test, is if a wrapped live collection, the biggest one, slows down somehow the angine a la DOMNodeInserted. I think no, but I am not sure yet.

    Regards

    ReplyDelete
  6. OK, no slowdown at all, and actually no benefits as well. The problem is that I am basing my tests with wrong timers, so it's 0 or it's 15/16, I cannot truly understand if I it is worth it. In any case, as document.getElementsByClassName, it's really fast :D

    ReplyDelete
  7. Can you elaborate on the tests you're doing? I don't understand what you mean by "The problem is that I am basing my tests with wrong timers, so it's 0 or it's 15/16"

    ReplyDelete
  8. J% I am taking the classic W3C page used in Taskspeed and others tests.

    I put the function on the top, zero differences.

    Then I perform a couple of searches, and I take time for each search.

    Under windows, timers are almost useless, cause the result for a call that took 8 ms, for example, will always e 15 or 16, and never 8. This problem has been explained in John Resig blog few months (years?) ago :)

    ReplyDelete
  9. I like your approach very much, thanks for sharing :)

    ReplyDelete
  10. It doesn't behave like a live collection... At least on IE8 SM. And it seems obvious to me, since ret is nothing more than an array.
    Am I missing something?

    If you want something like a static node list, you can check for querySelectorAll, which is provided by IE8 and should be a lot faster.

    Massimo

    ReplyDelete
  11. you are missing the childNodes variables ... please read again, test, understand, and ask more if necessary. Regards

    ReplyDelete
  12. Sorry to post again after 4 months...
    Yes, childNodes is indeed a live NodeList, but ret is just an Array. And we're just adding the matching elements to that array. So, the returned object is not a live list.

    That's what I wanted to say.
    IE8 still doesn't implement getElementsByClassName but implements querySelectorAll, so if you want to replicate getElementsByClassName you can use querySelectorAll instead, which return a non-live node collection.

    I understand that's not the point of your idea, which is to create a scope where you can define every function you want that can make a good use of the live NodeList of all the elements.
    So defining getElementsByClassName was just an example, I guess.

    ReplyDelete

Note: Only a member of this blog may post a comment.