Belt Error Perf

JavaScript performance comparison

Test case created by John Cockrell

Preparation code

 
<script>
Benchmark.prototype.setup = function() {
    /*
    *   belt.js
    *
    *   A general-purpose utility function. Used to extend
    *     and house my general-purpose js-utils.
    *
    */

    (function(global) {
   
    /*
    *   SETUP
    *
    *   Initialize public and private variables, and overwrite
    *     the `global.BELT` namespace, caching anything that might be there.
    *   Orient document, navigator, location to the global object, since we're
    *     operating inside a self-invoking function closure.
    *
    *   BELT     : Global namespace for utility functions.
    *
    *   _cache   : A private cache object accessed by BELT fns.
    *   _errors  : A private error queue; populated by BELT error logging.
    *   _belt    : A copy of anything in the `global.BELT` namespace, in case
    *              we end up overwriting something.
    *   _console : A copy of the `global.console` if it exists. BELT defaults to
    *              creating a safe copy of console in the global namespace,
    *              overwriting the normal `global.console`.
    *
    */

        var BELT = {},
            _cache = {},
            _errors = [],
   
            //  Make sure document, location, navigator are properly defined
            //    within the scope of this self-invoking function.
            document = global.document,
            location = global.location,
            navigator = global.navigator;
   
        //  Since we'll be overwriting global.BELT and global.console
        //    make the old values accessible via the _cache.
        _cache.global_BELT = global.BELT;
        _cache.global_console = global.console;
   
    /* ---------------- top ----------------- */
   
    /*
    *   CORE JS UTILITIES
    *
    *   Borrow various native functions for internal use.
    *   Any self-rolled object and array manipulation functions go here.
    *
    *   slice()
    *       Array.prototype.slice
    *
    *   push()
    *       Array.prototype.push
    *
    *   toString()
    *       Object.prototype.toString
    *
    *   hasOwnProperty()
    *       Object.prototype.hasOwnProperty
    *
    *   isArray()
    *       Checks if the thing passed in is an array.
    *       @arguments : something
    *       @return    : [boolean]
    *
    *   isObject()
    *       Checks if the thing passed in is an object.
    *       @arguments : something
    *       @return    : [boolean]
    *
    *   clone()
    *       Create a deep copy of an object via recursion.
    *       This is more effective than JSON.* means of cloning objects,
    *         since cloned functions are usable.
    *       This is for non-prototypal object literals and arrays, rather
    *         than constructed objects... for the moment.
    *       Currently outstrips jQuery.extend() [v 1.8.3] in performance
    *         by a significant margin : http://jsperf.com/belt-core-deep-clone
    *           @arguments : from [,to]
    *           @return    : [clone of object]
    *
    *   namespace()
    *       Return the tip of a namespace. If it doesn't exist yet, then
    *         create an object in this namespace.
    *       Using `BELT.namespace()` prevents accidental rewrites when
    *         working with big namespaces.
    *           @arguments : [string]
    *           @return    : [Object object]
    *
    *   inherit()
    *       A simple inheritance function.
    *           @arguments : parent, child /
    *                        {parent:, child:}
    *           @return    : ...
    *
    *   extend()
    *           @arguments : obj, extendWithProperties
    *           @return    : boolean
    *
    *   createConsoleAlias()
    *       The JavaScript global console object is not consistently implemented
    *       cross brwoser yet.
    *       This creates a `console` object to prevent script crashes when you
    *       attempt to access a method of an undefined object. Methods are aliased
    *       in stages based on browser availability.
    *       As far as I know, I've grouped the commands by availability in different
    *       browser environments. The most generic set, `ie_opera_ff_webkit` will
    *       work pretty reliably x-browser when you use it.
    *           @arguments : none
    *           @return    : Pseudo-console.
    *
    */

    (function defineCoreModule(BELT) {
        BELT.core = {};
        BELT.slice = BELT.core.slice = Array.prototype.slice;
        BELT.push = BELT.core.push = Array.prototype.push;
        BELT.toString = BELT.core.toString = Object.prototype.toString;
        BELT.hasOwnProperty = BELT.core.hasOwnProperty = Object.prototype.hasOwnProperty;
   
        BELT.isArray = BELT.core.isArray = function(it) {
            return (it instanceof Array);
        };
   
        BELT.isObject = BELT.core.isObject = function(it) {
            return (typeof it === 'object');
        };
   
        BELT.clone = BELT.core.clone = (function() {
   
            //  Private helper function for public clone() API.
            function recurse(from_i, doppel_i) {
                if (BELT.core.isArray(from_i) || BELT.core.isObject(from_i)) {
                    return BELT.core.clone(from_i, doppel_i);
                } else {
                    return from_i;
                }
            }
   
            return function(from, to) {
                var doppel,
                    i;
   
                if (BELT.core.isArray(from)) {
                    doppel = to || [];
                    for (i = 0; i < from.length; i += 1) {
                        doppel[i] = recurse(from[i], doppel[i]);
                    }
   
                } else if (BELT.core.isObject(from)) {
                    doppel = to || {};
                    for (i in from) {
                        doppel[i] = recurse(from[i], doppel[i]);
                     }
   
                } else {
                    doppel = from;
                }
   
                return doppel;
            };
        }());
   
        BELT.namespace = BELT.core.namespace = function(str) {
            var levels = str && str.split && str.split('.'),
                i = 0,
                name_space,
                step,
                msg;
   
            //  Fallthrough if incorrect usage.
            if (levels === undefined) {
                msg = 'BELT.namespace(str) : str can\'t be ' + str;
                throw new Error(msg);
            }
   
            //  Find the namespace (should be first str.)
            name_space = levels[0];
            step = global[levels[0]] || (global[levels[0]] = {});
            levels.shift();
   
            //  Iterate through the levels of the namespace string.
            for (; i < levels.length; i += 1) {
                if (typeof step[levels[i]] === 'undefined') {
                    step[levels[i]] = {};
   
                } else if (typeof step[levels[i]] === 'function') {
                    i += 1;
                    msg = 'BELT.namespace() : ' + name_space + '.';
                    msg += levels.slice(0, i).join('.') + ' is a function';
                    throw new Error(msg);
                }
   
                step = step[levels[i]];
            }
   
            return step;
        };
   
        BELT.inherit = BELT.core.inherit = function inherit(P, C) {
            var opt = typeof P === 'object' ?
                        P :
                        {parent:P, child:C},
                F = function() {};
   
            F.prototype = opt.parent.prototype;
            opt.child.prototype = new F();
            opt.child.prototype_chain = opt.parent.prototype_chain || [];
            opt.child.prototype_chain.push(opt.parent.prototype);
            opt.child.prototype.constructor = opt.child;
        };
   
   
        //  How to use to write plugins:
        //  BELT.extend(BELT.namespace('ns'), { props });
        BELT.extend = BELT.core.extend = function(obj, extendWithProperties) {
            console.error('WARNING: BELT.extend() incomplete.');
        };
   
        BELT.core.createConsoleAlias = function(){
           var new_console = new function BELTConsole() {},
                g_console = BELT.storage.get('global_console'),
                method_groups = {
                    ie_opera_ff_webkit: ['log', 'warn', 'error', 'info', 'assert', 'clear'],
                    opera_ff_webkit: ['dir', 'trace', 'profile', 'profileEnd', 'group', 'groupEnd'],
                    ff_webkit: ['debug', 'groupCollapsed', 'time', 'timeEnd', 'noSuchMethod'],
                    webkit: ['timeStamp', 'markTimeline', 'dirxml']
                },
                group,
                method,
                fn,
                i;
   
            for (group in method_groups) {
                for (i = 0; i < method_groups[group].length; i += 1) {
                    new_console[method_groups[group][i]] = (function(method) {
                        //  Must be called directly on console object, otherwise you
                        //    have IllegalInvocation errors.
                        if (g_console[method]) {
                            fn = function(a) { g_console[method](a) };
                        } else if (g_console['log']) {
                            fn = function(a) { g_console['log'](a) };
                        } else {
                            fn = function(){};
                        }
                        return fn;
                    }(method_groups[group][i]));
                }
            }
   
            //  Allow direct access to private Webkit Console APIs that aren't methods.
            new_console.memory = g_console.memory || {};
            new_console.profiles = g_console.profiles || {};
   
            //  Return aliased functions.
            return new_console;
        };
   
    }(BELT));
   
    /*
    *   PROBLEM
    *
    *   Error handling for your JS app.
    *
    *   reportProblem()
    *       Used for logging problems. ...?
    *           @arguments : message [, type][, fn_name]
    *                        { message:, [,type:] [,fn_name:] }
    *           @return    :
    *
    *   Err
    *       @arguments : message [, fn_name]
    *                    { message: [, fn_name:] }
    */

   
    (function defineProblemModule(BELT) {
        BELT.problem = {};    // namespace.
   
        //  Public API.
        BELT.reportProblem = BELT.problem.report = function(message, type, fn_name) {
            var opt = (typeof message === 'object') ?
                      message :
                      {message: message, type: type, fn_name: fn_name};
   
            //  Mandatory Arg: message.
            opt.message === undefined &&
                BELT.problem.report({ /* !!! Error message API */ });
   
            //  Processing ...
            console.error('Error: BELT.problem.report() incomplete.');
   
        };
   
   
        //  Constructors.
        BELT.problem.Error = function(message, fn_name) {
            var opt = typeof message === 'object' ?
                        message :
                        { message: message, fn_name: fn_name };
   
            this.type         = 'Error';
            this.name         = this.constructor.name || 'Error';
            this.message      = opt.message || 'Unhelpful generic error.';
            this.stack        = (new Error()).stack;
            this.timestamp    = BELT.date.timestamp();
            this.navigator_raw = global.navigator || 'Unavailable.';
            this.location_raw  = global.location || 'Unavailable.';
        };
        BELT.core.inherit(global.Error, BELT.problem.Error);
       
    }(BELT));
   
   
   
   
   
   
   
    /*
    *   STORAGE (CACHE)
    *
    *   storage.set()
    *       Set a key-value pair in the private _cache object.
    *           @arguments : key, value / {key:, value:}
    *           @returns   : true if success
    *
    *   storage.get()
    *       Retreive an item from the private _cache object.
    *           @arguments : key [string] / [empty]
    *           @return    : _cache.key / clone of _cache
    *
    */

    (function defineStorageModule(BELT) {
        BELT.storage = {};
   
        BELT.storage.set = function(key, value) {
            var opt = (typeof key === 'object') ?
                        key :
                        {key: key, value: value};
   
            //  Arg checking: overkill, but better than losing data.
            opt.key === undefined &&
                BELT.problem.report({/* !!! Error message API */});
            typeof opt.key !== 'string' &&
                BELT.problem.report({ /* !!! Error message API */});
            opt.value === undefined &&
                BELT.problem.report({ /* !!! Error message API */ });
   
            //  Set to private cache.
            _cache[opt.key] = opt.value;
        };
   
        BELT.storage.get = function(key) {
            if (key) { return _cache[key] }
            else { return BELT.core.clone(_cache) }
        };
    }(BELT));
   
   
   
    /*
    *   DATE
    *
    *   General purpose date handling module.
    *   Among other things, it shims `Date.now()` if it is not supported by
    *     the browser.
    *   `new Date().getTime()` outperforms `+(new Date)` by a fairly large margin,
    *     so that's the chosen shim.   http://jsperf.com/creating-timestamps
    *
    *   timestamp()
    *       Returns a unix timestamp.
    *
    */

    (function defineDateModule(BELT) {
        BELT.date = {};
   
        //  Shim for older ECMA (sub 1.5) engines.
        Date.now = Date.now || function now() {return new Date().getTime() };
   
        BELT.timestamp = BELT.date.timestamp = function() {
            return Math.floor(Date.now() / 1000);
        };
   
    }(BELT));
   
   
   
    /* ----------- bottom ------------- */
   
   
   
   
    /*
    *   EXPOSE/EXPORT
    *
    *   Create a safe console alias.
    *
    *   Expose local BELT variable to the global namespace, based on the
    *     global variable passed into this self-invoking function.
    *
    */

        global.console = BELT.core.createConsoleAlias();
        global.BELT = BELT;
   
    }(window));  //   Will either be GLOBAL (node) || window (browser)
};
</script>

Test runner

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

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Belt.error (no strings)
var e = new BELT.problem.Error('I am an error.');
var f = e.stack;
pending…
Native error
var e = new Error('I am an error.');
var f = e.stack;
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