4
\$\begingroup\$

I personally want a small selector function that covers the three common cases

  • getElementById
  • getElementsByClassName
  • getElementsByTagName

It should support contexts and should not support querySelectorAll since <opinionated> QSA is slow as hell and should be avoided </opinionated>

I have an implementation of such a function

function select(selector, context) {
    var c = selector.charAt(0),
        method;

    if (c === "#") {
        method = "getElementById";
        selector = selector.substring(1);
    } else if (c === ".") {
        method = "getElementsByClassName";
        selector = selector.substring(1);
    } else {
        method = "getElementsByTagName";
    }

    return (context || document)[method](selector);
}

And I have a benchmark.

As can be seen it's still a factor of 4 away from native support.

Can I hand optimise this further? And if so, how?

\$\endgroup\$

3 Answers 3

3
\$\begingroup\$

This is twice as slow as native (the original being 4x as slow)

function select (selector, context) {
    var c = selector.charAt(0), 
        method,
        context = context || document;

    if (c === '#') {
        selector = selector.substring(1);
        method = context.getElementById(selector);
    } 

    else if (c === '.') {
        selector = selector.substring(1);
        method = context.getElementsByClassName(selector);
    } 

    else {
        method = context.getElementsByTagName(selector);
    }

    return method
}
\$\endgroup\$
3
  • 2
    \$\begingroup\$ benchmarks confirm your function is either the same or faster. \$\endgroup\$
    – Raynos
    Dec 10, 2011 at 16:43
  • \$\begingroup\$ anything else that could be done? \$\endgroup\$ Dec 10, 2011 at 17:56
  • \$\begingroup\$ Fork chrome/firefox and hand optimise their C++ ? \$\endgroup\$
    – Raynos
    Dec 10, 2011 at 18:04
1
\$\begingroup\$

Well , you have to keep in mind that not all browsers implement getElementsByClassName, not even all of ( what you would call ) "proper browsers".

You should add a fallback for such a problem.

That said, you probably could get rid of at least one IF , if you use something like a { '.': 'getElementsByClassName', '#': 'getElementById' };. Just put said object into closure, otherwise you would be creating it each time anew.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I know getElementsByClassName doesn't work in IE8, I have a shim for that. \$\endgroup\$
    – Raynos
    Dec 10, 2011 at 16:19
  • \$\begingroup\$ I implemented your suggestion as select2. It's actually slightly slower. \$\endgroup\$
    – Raynos
    Dec 10, 2011 at 16:25
1
\$\begingroup\$

I'm not sure why no one has suggested a switch ?

As i understand it a switch will be equal or faster than if statements EDIT:- except chrome ... huh!?

switch(c)
{
    case '#':
        ...
        break; // or return
    case '.':
        ...
        break; // or return
    default
        ...
        break; // or return
}

http://jsperf.com/select-vs-natives-vs-jquery/6

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.