jQuery Common Ancestor

JavaScript performance comparison

Test case created by Erik E

Info

A performance exploration of the various jQuery plugin functions given as answers to the stackoverflow question find the closest common ancestor of a set of elements;

Preparation code

<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<div id="outer">
    <dl>
        <dt>Items:</dt>
        <dd>
            <ul>
                <li>Item 1<div id="1" class="item-info">...</div></li>
                <li>Item 2<div id="2" class="item-info">...</div></li>
                <li>Item 3<div id="3" class="item-info">...</div></li>
            </ul>
        </dd>
    </dl>
</div>
<script>
Benchmark.prototype.setup = function() {
    var
        author,
        selectorlist = ['.item-info', '.item-info, #ancestor, #h2', 'body, #outer'],
        selectorcount = selectorlist.length;
    var ancestorfns = {
        ErikE: function() { // common ancestor of 'body, div' is 'html'
            var i, l, current,
                compare = this.eq(0).parents().reverse(),
                pos = compare.length - 1;
            for (i = 1, l = this.length; i < l && pos > 0; i += 1) {
                current = this.eq(i).parents().reverse();
                pos = Math.min(pos, current.length - 1);
                while (compare[pos] !== current[pos]) {
                    pos -= 1;
                }
            }
            return compare.eq(pos);
        },
            ErikE_IncludeSelf: function() { // common ancestor of 'body, div' is 'body'
            var i, l, current,
                compare = this.eq(0).parents().reverse(),
                pos = compare.length;
            if (this.length === 0) {
                return this;
            }
            compare.push(this[0]); // because jQuery .andSelf() and .add() are SLOW
            for (i = 1, l = this.length; i < l && pos > 0; i += 1) {
                current = this.eq(i).parents().reverse();
                current.push(this[i]);
                pos = Math.min(pos, current.length - 1);
                while (compare[pos] !== current[pos]) {
                    pos -= 1;
                }
            }
            return compare.eq(pos);
        },  
        Trey: function(f) {
            //Set the variables for use;
            s = $(this);
            var i, j;
            var p = [];
            var pv = true;
   
            //make sure there is something to itterate over
            if (s.length > 0) {
   
                //build a multidimentional array of parents
                s.each(function() {
                    p.push($(this).parents());
                });
   
                //itterate through the parents of the first element starting at the closest
                for (i = 0; i < p[0].length; i++) {
   
                    //itterate through all elements after the first
                    for (j = 1; j < s.length; j++) {
   
                        //look for the current parent of the first element in each array
                        pv = ($.inArray(p[0][i], p[j]) != -1);
   
                        //if we are looking at the last element and it matchs, return that parent
                        if (pv == true && j == s.length - 1) return typeof(f) == 'string' ? $(p[0][i]).find(f) : $(p[0][i]);
                    }
                }
            }
            return false;
        },
        'Ricki Runge': function(f) {
            //Set the variables for use;
            s = $(this);
            var i, j;
            var p = [];
            var pv = true;
   
            //make sure there is something to itterate over
            if (s.length > 0) {
   
                //build a multidimentional array of parents
                s.each(function() {
                    p.push($(this).parents());
                });
   
                //itterate through the parents of the first element starting at the closest
                for (i = 0; i < p[0].length; i++) {
   
                    //itterate through all elements after the first
                    for (j = 1; j < s.length; j++) {
   
                        //look for the current parent of the first element in each array
                        pv = ($.inArray(p[0][i], p[j]) != -1);
   
                        //if we are looking at the last element and it matchs, return that parent
                        if (pv == true && j == s.length - 1) return typeof(f) == 'string' ? $(p[0][i]).find(f) : $(p[0][i]);
                    }
                }
            }
            return false;
        },
        'Jamie Wong': function() {
            var parents = [];
            var minlen = Infinity;
   
            $(this).each(function() {
                var curparents = $(this).parents();
                parents.push(curparents);
                minlen = Math.min(minlen, curparents.length);
            });
   
            for (var i in parents) {
                parents[i] = parents[i].slice(parents[i].length - minlen);
            }
   
            // Iterate until equality is found
            for (var i = 0; i < parents[0].length; i++) {
                var equal = true;
                for (var j in parents) {
                    if (parents[j][i] != parents[0][i]) {
                        equal = false;
                        break;
                    }
                }
                if (equal) return $(parents[0][i]);
            }
            return $([]);
        }
    };
   
    jQuery.fn.reverse = function() {
        return Array.prototype.reverse.call(this);
    };
   
    for (author in ancestorfns) {
       jQuery.fn['ancestorfn_' + author] = ancestorfns[author];
    }
   
    function doTest(author) {
       var i;
       for (i = 0; i < selectorcount; i += 1) {
          console.log(author, $(selectorlist[i])['ancestorfn_' + author]());
       }
    }
};
</script>

Preparation code output

Items:
  • Item 1
    ...
  • Item 2
    ...
  • Item 3
    ...

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
ErikE
doTest('ErikE');
pending…
ErikE_IncludeSelf
doTest('ErikE_IncludeSelf');
pending…
Trey
doTest('Trey');
pending…
Ricki Runge
doTest('Ricki Runge');
pending…
Jamie Wong
doTest('Jamie Wong');
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment