doc vs jquery

JavaScript performance comparison

Revision 8 of this test case created by Kory

Preparation code

<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var arrayProto = [],
    isList = require('./isList');
    getTargets = require('./getTargets'),
    getTarget = require('./getTarget'),
    document = {};

if(typeof window !== 'undefined'){
    document = window.document;
}

///[README.md]

function isIn(array, item){
    for(var i = 0; i < array.length; i++) {
        if(item === array[i]){
            return true;
        }
    }
}

/**

    ## .find

    finds elements that match the query within the scope of target

        //fluent
        doc(target).find(query)();

        //legacy
        doc.find(target, query);
*/


function find(target, query){
    target = getTargets(target);
    if(query == null){
        return target;
    }

    if(isList(target)){
        var results = [];
        for (var i = 0; i < target.length; i++) {
            var subResults = doc.find(target[i], query);
            for(var j = 0; j < subResults.length; j++) {
                if(!isIn(results, subResults[j])){
                    results.push(subResults[j]);
                }
            }
        }
        return results;
    }

    return target ? target.querySelectorAll(query) : [];
};

/**

    ## .findOne

    finds the first element that matches the query within the scope of target

        //fluent
        doc(target).findOne(query)();

        //legacy
        doc.findOne(target, query);
*/


function findOne(target, query){
    target = getTarget(target);
    if(query == null){
        return target;
    }

    if(isList(target)){
        var result;
        for (var i = 0; i < target.length; i++) {
            result = findOne(target[i], query);
            if(result){
                break;
            }
        }
        return result;
    }

    return target ? target.querySelector(query) : null;
};

/**

    ## .closest

    recurses up the DOM from the target node, checking if the current element matches the query

        //fluent
        doc(target).closest(query)();

        //legacy
        doc.closest(target, query);
*/


function closest(target, query){
    target = getTarget(target);

    if(isList(target)){
        target = target[0];
    }

    while(
        target &&
        target.ownerDocument &&
        !is(target, query)
    ){
        target = target.parentNode;
    }

    return target === document && target !== query ? null : target;
};

/**

    ## .is

    returns true if the target element matches the query

        //fluent
        doc(target).is(query)();

        //legacy
        doc.is(target, query);
*/


function is(target, query){
    target = getTarget(target);

    if(isList(target)){
        target = target[0];
    }

    if(!target.ownerDocument || typeof query !== 'string'){
        return target === query;
    }
    return target === query || arrayProto.indexOf.call(find(target.parentNode, query), target) >= 0;
};

/**

    ## .addClass

    adds classes to the target

        //fluent
        doc(target).addClass(query)();

        //legacy
        doc.addClass(target, query);
*/


function addClass(target, classes){
    target = getTargets(target);

    if(isList(target)){
        for (var i = 0; i < target.length; i++) {
            addClass(target[i], classes);
        }
        return this;
    }
    if(!classes){
        return this;
    }

    var classes = classes.split(' '),
        currentClasses = target.classList ? null : target.className.split(' ');

    for(var i = 0; i < classes.length; i++){
        var classToAdd = classes[i];
        if(!classToAdd || classToAdd === ' '){
            continue;
        }
        if(target.classList){
            target.classList.add(classToAdd);
        } else if(!currentClasses.indexOf(classToAdd)>=0){
            currentClasses.push(classToAdd);
        }
    }
    if(!target.classList){
        target.className = currentClasses.join(' ');
    }
    return this;
};

/**

    ## .removeClass

    removes classes from the target

        //fluent
        doc(target).removeClass(query)();

        //legacy
        doc.removeClass(target, query);
*/


function removeClass(target, classes){
    target = getTargets(target);

    if(isList(target)){
        for (var i = 0; i < target.length; i++) {
            removeClass(target[i], classes);
        }
        return this;
    }

    if(!classes){
        return this;
    }

    var classes = classes.split(' '),
        currentClasses = target.classList ? null : target.className.split(' ');

    for(var i = 0; i < classes.length; i++){
        var classToRemove = classes[i];
        if(!classToRemove || classToRemove === ' '){
            continue;
        }
        if(target.classList){
            target.classList.remove(classToRemove);
            continue;
        }
        var removeIndex = currentClasses.indexOf(classToRemove);
        if(removeIndex >= 0){
            currentClasses.splice(removeIndex, 1);
        }
    }
    if(!target.classList){
        target.className = currentClasses.join(' ');
    }
    return this;
};

function addEvent(settings){
    var target = getTarget(settings.target);
    if(target){
        target.addEventListener(settings.event, settings.callback, false);
    }else{
        console.warn('No elements matched the selector, so no events were bound.');
    }
}

/**

    ## .on

    binds a callback to a target when a DOM event is raised.

        //fluent
        doc(target/proxy).on(events, target[optional], callback)();

    note: if a target is passed to the .on function, doc's target will be used as the proxy.

        //legacy
        doc.on(events, target, query, proxy[optional]);
*/


function on(events, target, callback, proxy){

    target = getTargets(target);
    proxy = getTargets(proxy);

    // handles multiple targets
    if(isList(target)){
        var multiRemoveCallbacks = [];
        for (var i = 0; i < target.length; i++) {
            multiRemoveCallbacks.push(on(events, target[i], callback, proxy));
        }
        return function(){
            while(multiRemoveCallbacks.length){
                multiRemoveCallbacks.pop()();
            }
        };
    }

    // handles multiple proxies
    // Already handles multiple proxies and targets,
    // because the target loop calls this loop.
    if(isList(proxy)){
        var multiRemoveCallbacks = [];
        for (var i = 0; i < proxy.length; i++) {
            multiRemoveCallbacks.push(on(events, target, callback, proxy[i]));
        }
        return function(){
            while(multiRemoveCallbacks.length){
                multiRemoveCallbacks.pop()();
            }
        };
    }

    var removeCallbacks = [];

    if(typeof events === 'string'){
        events = events.split(' ');
    }

    for(var i = 0; i < events.length; i++){
        var eventSettings = {};
        if(proxy){
            if(proxy === true){
                proxy = document;
            }
            eventSettings.target = proxy;
            eventSettings.callback = function(event){
                var closestTarget = closest(event.target, target);
                if(closestTarget){
                    callback(event, closestTarget);
                }
            };
        }else{
            eventSettings.target = target;
            eventSettings.callback = callback;
        }

        eventSettings.event = events[i];

        addEvent(eventSettings);

        removeCallbacks.push(eventSettings);
    }

    return function(){
        while(removeCallbacks.length){
            var removeCallback = removeCallbacks.pop();
            getTarget(removeCallback.target).removeEventListener(removeCallback.event, removeCallback.callback);
        }
    }
};

/**

    ## .off

    removes events assigned to a target.

        //fluent
        doc(target/proxy).off(events, target[optional], callback)();

    note: if a target is passed to the .on function, doc's target will be used as the proxy.

        //legacy
        doc.off(events, target, callback, proxy);
*/


function off(events, target, callback, proxy){
    if(isList(target)){
        for (var i = 0; i < target.length; i++) {
            off(events, target[i], callback, proxy);
        }
        return this;
    }
    if(proxy instanceof Array){
        for (var i = 0; i < proxy.length; i++) {
            off(events, target, callback, proxy[i]);
        }
        return this;
    }

    if(typeof events === 'string'){
        events = events.split(' ');
    }

    if(typeof callback !== 'function'){
        proxy = callback;
        callback = null;
    }

    proxy = proxy ? getTarget(proxy) : document;

    var targets = find(target, proxy);

    for(var targetIndex = 0; targetIndex < targets.length; targetIndex++){
        var currentTarget = targets[targetIndex];

        for(var i = 0; i < events.length; i++){
            currentTarget.removeEventListener(events[i], callback);
        }
    }
    return this;
};

/**

    ## .append

    adds elements to a target

        //fluent
        doc(target).append(children);

        //legacy
        doc.append(target, children);
*/


function append(target, children){
    var target = getTarget(target),
        children = getTarget(children);

    if(isList(target)){
        target = target[0];
    }

    if(isList(children)){
        for (var i = 0; i < children.length; i++) {
            append(target, children[i]);
        }
        return;
    }

    target.appendChild(children);
};

/**

    ## .prepend

    adds elements to the front of a target

        //fluent
        doc(target).prepend(children);

        //legacy
        doc.prepend(target, children);
*/


function prepend(target, children){
    var target = getTarget(target),
        children = getTarget(children);

    if(isList(target)){
        target = target[0];
    }

    if(isList(children)){
        //reversed because otherwise the would get put in in the wrong order.
        for (var i = children.length -1; i; i--) {
            prepend(target, children[i]);
        }
        return;
    }

    target.insertBefore(children, target.firstChild);
};

/**

    ## .isVisible

    checks if an element or any of its parents display properties are set to 'none'

        //fluent
        doc(target).isVisible();

        //legacy
        doc.isVisible(target);
*/


function isVisible(target){
    var target = getTarget(target);
    if(!target){
        return;
    }
    if(isList(target)){
        var i = -1;

        while (target[i++] && isVisible(target[i])) {}
        return target.length >= i;
    }
    while(target.parentNode && target.style.display !== 'none'){
        target = target.parentNode;
    }

    return target === document;
};

var doc = {};
doc.find = find;
doc.findOne = findOne;
doc.closest = closest;
doc.is = is;
doc.addClass = addClass;
doc.removeClass = removeClass;
doc.off = off;
doc.on = on;
doc.append = append;
doc.prepend = prepend;
doc.isVisible = isVisible;

module.exports = doc;
},{"./getTarget":3,"./getTargets":4,"./isList":5}],2:[function(require,module,exports){
var arrayProto = [],
    doc = require('./doc'),
    isList = require('./isList'),
    getTargets = require('./getTargets'),
    document = {};

if(typeof window !== 'undefined'){
    document = window.document;
}

flocProto = {};

function Floc(target){
    var instance = getTargets(target);

    if(!isList(instance)){
        if(instance){
            instance = [instance];
        }else{
            instance = [];
        }
    }

    instance.__proto__ = flocProto;
    return instance;
}

for(var key in doc){
    if(typeof doc[key] === 'function'){
        Floc[key] = doc[key];
        flocProto[key] = (function(key){
            return function(a,b,c,d,e,f){
                var result = doc[key](this, a,b,c,d,e,f);

                if(result !== doc && isList(result)){
                    return Floc(result);
                }
                return result;
            };
        }(key));
    }
}
flocProto.on = function(events, target, callback){
    var proxy = this;
    if(typeof target === 'function'){
        callback = target;
        target = this;
        proxy = null;
    }
    doc.on(events, target, callback, proxy);
    return this;
};

flocProto.off = function(events, target, callback){
    var reference = this;
    if(typeof target === 'function'){
        callback = target;
        target = this;
        reference = null;
    }
    doc.off(events, target, callback, reference);
    return this;
};

module.exports = window.doc = Floc;
},{"./doc":1,"./getTargets":4,"./isList":5}],3:[function(require,module,exports){
var singleId = /^#\w+$/;

module.exports = function getTarget(target){
    if(typeof target === 'string'){
        if(singleId.exec(target)){
            return document.getElementById(target.slice(1));
        }
        return document.querySelector(target);
    }

    return target;
}
},{}],4:[function(require,module,exports){

var singleClass = /^\.\w+$/,
    singleId = /^#\w+$/,
    singleTag = /^\w+$/;

module.exports = function getTargets(target){
    if(typeof target === 'string'){
        if(singleId.exec(target)){
            // If you have more than 1 of the same id in your page,
            // thats your own stupid fault.
            return [document.getElementById(target.slice(1))];
        }
        if(singleTag.exec(target)){
            return document.getElementsByTagName(target);
        }
        if(singleClass.exec(target)){
            return document.getElementsByClassName(target.slice(1));
        }
        return document.querySelectorAll(target);
    }

    return target;
};
},{}],5:[function(require,module,exports){
module.exports = function isList(object){
    return object instanceof Array || object && typeof object === 'object' && 'length' in object;
}
},{}]},{},[2])
;
</script>



<div class="content" id="main"><span class="ctr-p" id="body" data-jiis="bp"><center><div id="lga" style="height:231px;margin-top:20px"><img alt="Google" height="95" src="/images/srpr/logo11w.png" width="269" id="hplogo" onload="window.lol&amp;&amp;lol()" style="padding-top:112px"></div><div style="height:102px"></div><div id="prm-pt" style="font-size:83%;min-height:3.5em"><br></div></center></span><div class="ctr-p" id="footer" data-jiis="bp">  <span style="display:none">&nbsp;</span> <div id="footcnt"><style>.fhp{bottom:0;left:0;position:absolute;right:0}.fbar p{color:#777;display:inline}.fbar a,#fsettl{color:#777;text-decoration:none;white-space:nowrap}.fbar a:hover{color:#333}.fbard a:hover{text-decoration:underline}.fdl img{margin-right:4px}.fdl a,.fbarh #swml a{text-decoration:none}.fmulti{text-align:center}.fmulti #fsr{display:block;float:none}.fmulti #fuser{display:block;float:none}#fsr{float:right;white-space:nowrap}#fsl{white-space:nowrap}.fbard #fsettl:hover{text-decoration:underline}.fbard #fsett a:hover{text-decoration:underline}.fbtnr,.fbtnl{height:13px;width:8px}.fbtnr:before,.fbtnl:before{border:8px solid rgba(255,255,255,0);border-radius:8px;content:'';position:absolute}.fbtnr:before{border-left:8px solid #777;left:1px}.fbtnl:before{border-right:8px solid #777;left:-9px}.fbtnr:after,.fbtnl:after{border:12px solid rgba(255,255,255,0);content:'';position:absolute;top:-4px}.fbtnr:after{border-left:10px solid #f6f6f6;left:-4px}.fbtnl:after{border-right:10px solid #f6f6f6;left:-10px}.fbtns-card .fbtnr:after{border-left:10px solid white}.fbtns-card .fbtnl:after{border-right:10px solid white}.fbar>.nes{line-height:22px}.fbar .fbl{padding:0 0 0 27px !important;margin:0 !important}.fbar .fblf{padding:0 !important;margin:0 !important}</style> <style>.fbar{background:#f2f2f2;border-top:1px solid #e4e4e4;font-size:small;line-height:40px;min-width:980px}.fbarspacing{margin-left:135px}</style> <style>#fsl{margin-left:30px}#fsr{margin-right:30px}.fmulti #fsl{margin-left:0}.fmulti #fsr{margin-right:0}</style> <div class="fhp fbard" id="fbar"> <div class="fbar"> <span id="fsr">  <a class="fblf" href="/intl/en/policies/?fg=1" style="white-space:normal"> <span style="color:#b14436">New</span> Privacy &amp; Terms</a>  <span style="display:inline-block;position:relative"><style>#fsett{background:#fff;border:1px solid #999;bottom:30px;padding:10px 0;position:absolute;box-shadow:0 2px 4px rgba(0,0,0,0.2);-webkit-box-shadow:0 2px 4px rgba(0,0,0,0.2);text-align:left;z-index:100}#fsett a{color:#777;display:block;line-height:44px;padding:0 20px;text-decoration:none;white-space:nowrap}#fsett a:hover{color:#333}</style> <a href="https://www.google.com/preferences?hl=en" class="fbl" jsaction="foot.cst" id="fsettl">Settings</a> <span id="fsett" style="display:none"> <a href="https://www.google.com/preferences?hl=en&amp;fg=1">Search settings</a> <span data-jibp="h" data-jiis="uc" id="advsl"> <a href="/advanced_search?hl=en&amp;fg=1">Advanced search</a> </span> <a href="/history?hl=en&amp;fg=1">Web History</a> <a href="//support.google.com/websearch/?p=ws_results_help&amp;hl=en&amp;fg=1">Search Help</a> <a href="javascript:void(0)" data-bucket="websearch" jsaction="gf.sf" target="_blank" id="fblqf" data-ved="0CAYQLg">  Send feedback </a> </span> </span>  <a class="fbl" href="https://www.google.com/setprefdomain?prefdom=AU&amp;prev=https://www.google.com.au/&amp;sig=0_EXhzOBw1ldse-wRdDyW3aIvOSZY%3D&amp;fg=1">Google.com.au</a> </span> <span id="fsl"> <a class="fblf" href="/intl/en/ads/?fg=1">Advertising</a> <a class="fbl" href="/services/?fg=1">Business</a> <a class="fbl" href="/intl/en/about.html?fg=1">About</a> </span>  </div>  </div> </div>  </div></div>

Preparation code output


Test runner

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

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
floc().find()
doc('#lga').find('.ctr-p');
pending…
jquery().find()
$('#lga').find('.ctr-p');
pending…
doc find old
doc.find('#lga', '.ctr-p');
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