wqfwewefewrw

JavaScript performance comparison

Revision 28 of this test case created

Preparation code

<script src="https://rawgithub.com/petkaantonov/bluebird/master/js/browser/bluebird.js">
</script>
<script src="http://rawgithub.com/kriskowal/q/v0.9.6/q.min.js"></script>

<script src="https://rawgithub.com/rkatic/p/master/p.min.js"></script>

    <script>
        define = function( factory ) {
            when = factory();
        };
        define.amd = {};
    </script>
<script>
/** @license MIT License (c) copyright 2011-2013 original author or authors */

/**
 * A lightweight CommonJS Promises/A and when() implementation
 * when is part of the cujo.js family of libraries (http://cujojs.com/)
 *
 * Licensed under the MIT License at:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @author Brian Cavalier
 * @author John Hann
 * @version 2.5.0
 */

(function(define, global) { 'use strict';
define(function (require) {

        // Public API

        when.promise   = promise;    // Create a pending promise
        when.resolve   = resolve;    // Create a resolved promise
        when.reject    = reject;     // Create a rejected promise
        when.defer     = defer;      // Create a {promise, resolver} pair

        when.join      = join;       // Join 2 or more promises

        when.all       = all;        // Resolve a list of promises
        when.map       = map;        // Array.map() for promises
        when.reduce    = reduce;     // Array.reduce() for promises
        when.settle    = settle;     // Settle a list of promises

        when.any       = any;        // One-winner race
        when.some      = some;       // Multi-winner race

        when.isPromise = isPromiseLike;  // DEPRECATED: use isPromiseLike
        when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable

        /**
         * Register an observer for a promise or immediate value.
         *
         * @param {*} promiseOrValue
         * @param {function?} [onFulfilled] callback to be called when promiseOrValue is
         *   successfully fulfilled.  If promiseOrValue is an immediate value, callback
         *   will be invoked immediately.
         * @param {function?} [onRejected] callback to be called when promiseOrValue is
         *   rejected.
         * @param {function?} [onProgress] callback to be called when progress updates
         *   are issued for promiseOrValue.
         * @returns {Promise} a new {@link Promise} that will complete with the return
         *   value of callback or errback or the completion value of promiseOrValue if
         *   callback and/or errback is not supplied.
         */

        function when(promiseOrValue, onFulfilled, onRejected, onProgress) {
                // Get a trusted promise for the input promiseOrValue, and then
                // register promise handlers
                return resolve(promiseOrValue).then(onFulfilled, onRejected, onProgress);
        }

        /**
         * Trusted Promise constructor.  A Promise created from this constructor is
         * a trusted when.js promise.  Any other duck-typed promise is considered
         * untrusted.
         * @constructor
         * @param {function} sendMessage function to deliver messages to the promise's handler
         * @param {function?} inspect function that reports the promise's state
         * @name Promise
         */

        function Promise(sendMessage, inspect) {
                this._message = sendMessage;
                this.inspect = inspect;
        }

        Promise.prototype = {
                /**
                 * Register handlers for this promise.
                 * @param [onFulfilled] {Function} fulfillment handler
                 * @param [onRejected] {Function} rejection handler
                 * @param [onProgress] {Function} progress handler
                 * @return {Promise} new Promise
                 */

                then: function(onFulfilled, onRejected, onProgress) {
                        /*jshint unused:false*/
                        var args, sendMessage;

                        args = arguments;
                        sendMessage = this._message;

                        return _promise(function(resolve, reject, notify) {
                                sendMessage('when', args, resolve, notify);
                        }, this._status && this._status.observed());
                },

                /**
                 * Register a rejection handler.  Shortcut for .then(undefined, onRejected)
                 * @param {function?} onRejected
                 * @return {Promise}
                 */

                otherwise: function(onRejected) {
                        return this.then(undef, onRejected);
                },

                /**
                 * Ensures that onFulfilledOrRejected will be called regardless of whether
                 * this promise is fulfilled or rejected.  onFulfilledOrRejected WILL NOT
                 * receive the promises' value or reason.  Any returned value will be disregarded.
                 * onFulfilledOrRejected may throw or return a rejected promise to signal
                 * an additional error.
                 * @param {function} onFulfilledOrRejected handler to be called regardless of
                 *  fulfillment or rejection
                 * @returns {Promise}
                 */

                ensure: function(onFulfilledOrRejected) {
                        return this.then(injectHandler, injectHandler)['yield'](this);

                        function injectHandler() {
                                return resolve(onFulfilledOrRejected());
                        }
                },

                /**
                 * Shortcut for .then(function() { return value; })
                 * @param  {*} value
                 * @return {Promise} a promise that:
                 *  - is fulfilled if value is not a promise, or
                 *  - if value is a promise, will fulfill with its value, or reject
                 *    with its reason.
                 */

                'yield': function(value) {
                        return this.then(function() {
                                return value;
                        });
                },

                /**
                 * Runs a side effect when this promise fulfills, without changing the
                 * fulfillment value.
                 * @param {function} onFulfilledSideEffect
                 * @returns {Promise}
                 */

                tap: function(onFulfilledSideEffect) {
                        return this.then(onFulfilledSideEffect)['yield'](this);
                },

                /**
                 * Assumes that this promise will fulfill with an array, and arranges
                 * for the onFulfilled to be called with the array as its argument list
                 * i.e. onFulfilled.apply(undefined, array).
                 * @param {function} onFulfilled function to receive spread arguments
                 * @return {Promise}
                 */

                spread: function(onFulfilled) {
                        return this.then(function(array) {
                                // array may contain promises, so resolve its contents.
                                return all(array, function(array) {
                                        return onFulfilled.apply(undef, array);
                                });
                        });
                },

                /**
                 * Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected)
                 * @deprecated
                 */

                always: function(onFulfilledOrRejected, onProgress) {
                        return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress);
                }
        };

        /**
         * Returns a resolved promise. The returned promise will be
         *  - fulfilled with promiseOrValue if it is a value, or
         *  - if promiseOrValue is a promise
         *    - fulfilled with promiseOrValue's value after it is fulfilled
         *    - rejected with promiseOrValue's reason after it is rejected
         * @param  {*} value
         * @return {Promise}
         */

        function resolve(value) {
                return promise(function(resolve) {
                        resolve(value);
                });
        }

        /**
         * Returns a rejected promise for the supplied promiseOrValue.  The returned
         * promise will be rejected with:
         * - promiseOrValue, if it is a value, or
         * - if promiseOrValue is a promise
         *   - promiseOrValue's value after it is fulfilled
         *   - promiseOrValue's reason after it is rejected
         * @param {*} promiseOrValue the rejected value of the returned {@link Promise}
         * @return {Promise} rejected {@link Promise}
         */

        function reject(promiseOrValue) {
                return when(promiseOrValue, rejected);
        }

        /**
         * Creates a {promise, resolver} pair, either or both of which
         * may be given out safely to consumers.
         * The resolver has resolve, reject, and progress.  The promise
         * has then plus extended promise API.
         *
         * @return {{
         * promise: Promise,
         * resolve: function:Promise,
         * reject: function:Promise,
         * notify: function:Promise
         * resolver: {
         *      resolve: function:Promise,
         *      reject: function:Promise,
         *      notify: function:Promise
         * }}}
         */

        function defer() {
                var deferred, pending, resolved;

                // Optimize object shape
                deferred = {
                        promise: undef, resolve: undef, reject: undef, notify: undef,
                        resolver: { resolve: undef, reject: undef, notify: undef }
                };

                deferred.promise = pending = promise(makeDeferred);

                return deferred;

                function makeDeferred(resolvePending, rejectPending, notifyPending) {
                        deferred.resolve = deferred.resolver.resolve = function(value) {
                                if(resolved) {
                                        return resolve(value);
                                }
                                resolved = true;
                                resolvePending(value);
                                return pending;
                        };

                        deferred.reject  = deferred.resolver.reject  = function(reason) {
                                if(resolved) {
                                        return resolve(rejected(reason));
                                }
                                resolved = true;
                                rejectPending(reason);
                                return pending;
                        };

                        deferred.notify  = deferred.resolver.notify  = function(update) {
                                notifyPending(update);
                                return update;
                        };
                }
        }

        /**
         * Creates a new promise whose fate is determined by resolver.
         * @param {function} resolver function(resolve, reject, notify)
         * @returns {Promise} promise whose fate is determine by resolver
         */

        function promise(resolver) {
                return _promise(resolver, monitorApi.PromiseStatus && monitorApi.PromiseStatus());
        }

        /**
         * Creates a new promise, linked to parent, whose fate is determined
         * by resolver.
         * @param {function} resolver function(resolve, reject, notify)
         * @param {Promise?} status promise from which the new promise is begotten
         * @returns {Promise} promise whose fate is determine by resolver
         * @private
         */

        function _promise(resolver, status) {
                var self, value, consumers = [];

                self = new Promise(_message, inspect);
                self._status = status;

                // Call the provider resolver to seal the promise's fate
                try {
                        resolver(promiseResolve, promiseReject, promiseNotify);
                } catch(e) {
                        promiseReject(e);
                }

                // Return the promise
                return self;

                /**
                 * Private message delivery. Queues and delivers messages to
                 * the promise's ultimate fulfillment value or rejection reason.
                 * @private
                 * @param {String} type
                 * @param {Array} args
                 * @param {Function} resolve
                 * @param {Function} notify
                 */

                function _message(type, args, resolve, notify) {
                        consumers ? consumers.push(deliver) : enqueue(function() { deliver(value); });

                        function deliver(p) {
                                p._message(type, args, resolve, notify);
                        }
                }

                /**
                 * Returns a snapshot of the promise's state at the instant inspect()
                 * is called. The returned object is not live and will not update as
                 * the promise's state changes.
                 * @returns {{ state:String, value?:*, reason?:* }} status snapshot
                 *  of the promise.
                 */

                function inspect() {
                        return value ? value.inspect() : toPendingState();
                }

                /**
                 * Transition from pre-resolution state to post-resolution state, notifying
                 * all listeners of the ultimate fulfillment or rejection
                 * @param {*|Promise} val resolution value
                 */

                function promiseResolve(val) {
                        if(!consumers) {
                                return;
                        }

                        value = coerce(self, val);
                        scheduleConsumers(consumers, value);
                        consumers = undef;

                        if(status) {
                                updateStatus(value, status);
                        }
                }

                /**
                 * Reject this promise with the supplied reason, which will be used verbatim.
                 * @param {*} reason reason for the rejection
                 */

                function promiseReject(reason) {
                        promiseResolve(rejected(reason));
                }

                /**
                 * Issue a progress event, notifying all progress listeners
                 * @param {*} update progress event payload to pass to all listeners
                 */

                function promiseNotify(update) {
                        if(consumers) {
                                scheduleConsumers(consumers, progressed(update));
                        }
                }
        }

        /**
         * Creates a fulfilled, local promise as a proxy for a value
         * NOTE: must never be exposed
         * @param {*} value fulfillment value
         * @returns {Promise}
         */

        function fulfilled(value) {
                return near(
                        new NearFulfilledProxy(value),
                        function() { return toFulfilledState(value); }
                );
        }

        /**
         * Creates a rejected, local promise with the supplied reason
         * NOTE: must never be exposed
         * @param {*} reason rejection reason
         * @returns {Promise}
         */

        function rejected(reason) {
                return near(
                        new NearRejectedProxy(reason),
                        function() { return toRejectedState(reason); }
                );
        }

        /**
         * Creates a near promise using the provided proxy
         * NOTE: must never be exposed
         * @param {object} proxy proxy for the promise's ultimate value or reason
         * @param {function} inspect function that returns a snapshot of the
         *  returned near promise's state
         * @returns {Promise}
         */

        function near(proxy, inspect) {
                return new Promise(function (type, args, resolve) {
                        try {
                                resolve(proxy[type].apply(proxy, args));
                        } catch(e) {
                                resolve(rejected(e));
                        }
                }, inspect);
        }

        /**
         * Create a progress promise with the supplied update.
         * @private
         * @param {*} update
         * @return {Promise} progress promise
         */

        function progressed(update) {
                return new Promise(function (type, args, _, notify) {
                        var onProgress = args[2];
                        try {
                                notify(typeof onProgress === 'function' ? onProgress(update) : update);
                        } catch(e) {
                                notify(e);
                        }
                });
        }

        /**
         * Coerces x to a trusted Promise
         *
         * @private
         * @param {*} x thing to coerce
         * @returns {*} Guaranteed to return a trusted Promise.  If x
         *   is trusted, returns x, otherwise, returns a new, trusted, already-resolved
         *   Promise whose resolution value is:
         *   * the resolution value of x if it's a foreign promise, or
         *   * x if it's a value
         */

        function coerce(self, x) {
                if (x === self) {
                        return rejected(new TypeError());
                }

                if (x instanceof Promise) {
                        return x;
                }

                if (!(x === Object(x) && 'then' in x)) {
                        return fulfilled(x);
                }

                return promise(function(resolve, reject, notify) {
                        enqueue(function() {
                                try {
                                        // We must check and assimilate in the same tick, but not the
                                        // current tick, careful only to access promiseOrValue.then once.
                                        var untrustedThen = x.then;

                                        if(typeof untrustedThen === 'function') {
                                                fcall(untrustedThen, x, resolve, reject, notify);
                                        } else {
                                                // It's a value, create a fulfilled wrapper
                                                resolve(fulfilled(x));
                                        }

                                } catch(e) {
                                        // Something went wrong, reject
                                        reject(e);
                                }
                        });
                });
        }

        /**
         * Proxy for a near, fulfilled value
         * @param {*} value
         * @constructor
         */

        function NearFulfilledProxy(value) {
                this.value = value;
        }

        NearFulfilledProxy.prototype.when = function(onResult) {
                return typeof onResult === 'function' ? onResult(this.value) : this.value;
        };

        /**
         * Proxy for a near rejection
         * @param {*} reason
         * @constructor
         */

        function NearRejectedProxy(reason) {
                this.reason = reason;
        }

        NearRejectedProxy.prototype.when = function(_, onError) {
                if(typeof onError === 'function') {
                        return onError(this.reason);
                } else {
                        throw this.reason;
                }
        };

        /**
         * Schedule a task that will process a list of handlers
         * in the next queue drain run.
         * @private
         * @param {Array} handlers queue of handlers to execute
         * @param {*} value passed as the only arg to each handler
         */

        function scheduleConsumers(handlers, value) {
                enqueue(function() {
                        var handler, i = 0;
                        while (handler = handlers[i++]) {
                                handler(value);
                        }
                });
        }

        function updateStatus(value, status) {
                value.then(statusFulfilled, statusRejected);

                function statusFulfilled() { status.fulfilled(); }
                function statusRejected(r) { status.rejected(r); }
        }

        /**
         * Determines if x is promise-like, i.e. a thenable object
         * NOTE: Will return true for *any thenable object*, and isn't truly
         * safe, since it may attempt to access the `then` property of x (i.e.
         *  clever/malicious getters may do weird things)
         * @param {*} x anything
         * @returns {boolean} true if x is promise-like
         */

        function isPromiseLike(x) {
                return x && typeof x.then === 'function';
        }

        /**
         * Initiates a competitive race, returning a promise that will resolve when
         * howMany of the supplied promisesOrValues have resolved, or will reject when
         * it becomes impossible for howMany to resolve, for example, when
         * (promisesOrValues.length - howMany) + 1 input promises reject.
         *
         * @param {Array} promisesOrValues array of anything, may contain a mix
         *      of promises and values
         * @param howMany {number} number of promisesOrValues to resolve
         * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
         * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
         * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
         * @returns {Promise} promise that will resolve to an array of howMany values that
         *  resolved first, or will reject with an array of
         *  (promisesOrValues.length - howMany) + 1 rejection reasons.
         */

        function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) {

                return when(promisesOrValues, function(promisesOrValues) {

                        return promise(resolveSome).then(onFulfilled, onRejected, onProgress);

                        function resolveSome(resolve, reject, notify) {
                                var toResolve, toReject, values, reasons, fulfillOne, rejectOne, len, i;

                                len = promisesOrValues.length >>> 0;

                                toResolve = Math.max(0, Math.min(howMany, len));
                                values = [];

                                toReject = (len - toResolve) + 1;
                                reasons = [];

                                // No items in the input, resolve immediately
                                if (!toResolve) {
                                        resolve(values);

                                } else {
                                        rejectOne = function(reason) {
                                                reasons.push(reason);
                                                if(!--toReject) {
                                                        fulfillOne = rejectOne = identity;
                                                        reject(reasons);
                                                }
                                        };

                                        fulfillOne = function(val) {
                                                // This orders the values based on promise resolution order
                                                values.push(val);
                                                if (!--toResolve) {
                                                        fulfillOne = rejectOne = identity;
                                                        resolve(values);
                                                }
                                        };

                                        for(i = 0; i < len; ++i) {
                                                if(i in promisesOrValues) {
                                                        when(promisesOrValues[i], fulfiller, rejecter, notify);
                                                }
                                        }
                                }

                                function rejecter(reason) {
                                        rejectOne(reason);
                                }

                                function fulfiller(val) {
                                        fulfillOne(val);
                                }
                        }
                });
        }

        /**
         * Initiates a competitive race, returning a promise that will resolve when
         * any one of the supplied promisesOrValues has resolved or will reject when
         * *all* promisesOrValues have rejected.
         *
         * @param {Array|Promise} promisesOrValues array of anything, may contain a mix
         *      of {@link Promise}s and values
         * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
         * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
         * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
         * @returns {Promise} promise that will resolve to the value that resolved first, or
         * will reject with an array of all rejected inputs.
         */

        function any(promisesOrValues, onFulfilled, onRejected, onProgress) {

                function unwrapSingleResult(val) {
                        return onFulfilled ? onFulfilled(val[0]) : val[0];
                }

                return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress);
        }

        /**
         * Return a promise that will resolve only once all the supplied promisesOrValues
         * have resolved. The resolution value of the returned promise will be an array
         * containing the resolution values of each of the promisesOrValues.
         * @memberOf when
         *
         * @param {Array|Promise} promisesOrValues array of anything, may contain a mix
         *      of {@link Promise}s and values
         * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
         * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
         * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
         * @returns {Promise}
         */

        function all(promisesOrValues, onFulfilled, onRejected, onProgress) {
                return _map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress);
        }

        /**
         * Joins multiple promises into a single returned promise.
         * @return {Promise} a promise that will fulfill when *all* the input promises
         * have fulfilled, or will reject when *any one* of the input promises rejects.
         */

        function join(/* ...promises */) {
                return _map(arguments, identity);
        }

        /**
         * Settles all input promises such that they are guaranteed not to
         * be pending once the returned promise fulfills. The returned promise
         * will always fulfill, except in the case where `array` is a promise
         * that rejects.
         * @param {Array|Promise} array or promise for array of promises to settle
         * @returns {Promise} promise that always fulfills with an array of
         *  outcome snapshots for each input promise.
         */

        function settle(array) {
                return _map(array, toFulfilledState, toRejectedState);
        }

        /**
         * Promise-aware array map function, similar to `Array.prototype.map()`,
         * but input array may contain promises or values.
         * @param {Array|Promise} array array of anything, may contain promises and values
         * @param {function} mapFunc map function which may return a promise or value
         * @returns {Promise} promise that will fulfill with an array of mapped values
         *  or reject if any input promise rejects.
         */

        function map(array, mapFunc) {
                return _map(array, mapFunc);
        }

        /**
         * Internal map that allows a fallback to handle rejections
         * @param {Array|Promise} array array of anything, may contain promises and values
         * @param {function} mapFunc map function which may return a promise or value
         * @param {function?} fallback function to handle rejected promises
         * @returns {Promise} promise that will fulfill with an array of mapped values
         *  or reject if any input promise rejects.
         */

        function _map(array, mapFunc, fallback) {
                return when(array, function(array) {

                        return _promise(resolveMap);

                        function resolveMap(resolve, reject, notify) {
                                var results, len, toResolve, i;

                                // Since we know the resulting length, we can preallocate the results
                                // array to avoid array expansions.
                                toResolve = len = array.length >>> 0;
                                results = [];

                                if(!toResolve) {
                                        resolve(results);
                                        return;
                                }

                                // Since mapFunc may be async, get all invocations of it into flight
                                for(i = 0; i < len; i++) {
                                        if(i in array) {
                                                resolveOne(array[i], i);
                                        } else {
                                                --toResolve;
                                        }
                                }

                                function resolveOne(item, i) {
                                        when(item, mapFunc, fallback).then(function(mapped) {
                                                results[i] = mapped;

                                                if(!--toResolve) {
                                                        resolve(results);
                                                }
                                        }, reject, notify);
                                }
                        }
                });
        }

        /**
         * Traditional reduce function, similar to `Array.prototype.reduce()`, but
         * input may contain promises and/or values, and reduceFunc
         * may return either a value or a promise, *and* initialValue may
         * be a promise for the starting value.
         *
         * @param {Array|Promise} promise array or promise for an array of anything,
         *      may contain a mix of promises and values.
         * @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total),
         *      where total is the total number of items being reduced, and will be the same
         *      in each call to reduceFunc.
         * @returns {Promise} that will resolve to the final reduced value
         */

        function reduce(promise, reduceFunc /*, initialValue */) {
                var args = fcall(slice, arguments, 1);

                return when(promise, function(array) {
                        var total;

                        total = array.length;

                        // Wrap the supplied reduceFunc with one that handles promises and then
                        // delegates to the supplied.
                        args[0] = function (current, val, i) {
                                return when(current, function (c) {
                                        return when(val, function (value) {
                                                return reduceFunc(c, value, i, total);
                                        });
                                });
                        };

                        return reduceArray.apply(array, args);
                });
        }

        // Snapshot states

        /**
         * Creates a fulfilled state snapshot
         * @private
         * @param {*} x any value
         * @returns {{state:'fulfilled',value:*}}
         */

        function toFulfilledState(x) {
                return { state: 'fulfilled', value: x };
        }

        /**
         * Creates a rejected state snapshot
         * @private
         * @param {*} x any reason
         * @returns {{state:'rejected',reason:*}}
         */

        function toRejectedState(x) {
                return { state: 'rejected', reason: x };
        }

        /**
         * Creates a pending state snapshot
         * @private
         * @returns {{state:'pending'}}
         */

        function toPendingState() {
                return { state: 'pending' };
        }

        //
        // Internals, utilities, etc.
        //

        var reduceArray, slice, fcall, nextTick, handlerQueue,
                setTimeout, funcProto, call, arrayProto, monitorApi,
                cjsRequire, MutationObserver, undef;

        cjsRequire = require;

        //
        // Shared handler queue processing
        //
        // Credit to Twisol (https://github.com/Twisol) for suggesting
        // this type of extensible queue + trampoline approach for
        // next-tick conflation.

        handlerQueue = [];

        /**
         * Enqueue a task. If the queue is not currently scheduled to be
         * drained, schedule it.
         * @param {function} task
         */

        function enqueue(task) {
                if(handlerQueue.push(task) === 1) {
                        nextTick(drainQueue);
                }
        }

        /**
         * Drain the handler queue entirely, being careful to allow the
         * queue to be extended while it is being processed, and to continue
         * processing until it is truly empty.
         */

        function drainQueue() {
                var task, i = 0;

                while(task = handlerQueue[i++]) {
                        task();
                }

                handlerQueue = [];
        }

        // capture setTimeout to avoid being caught by fake timers
        // used in time based tests
        setTimeout = global.setTimeout;

        // Allow attaching the monitor to when() if env has no console
        monitorApi = typeof console != 'undefined' ? console : when;

        // Sniff "best" async scheduling option
        // Prefer process.nextTick or MutationObserver, then check for
        // vertx and finally fall back to setTimeout
        /*global process*/
        if (typeof process === 'object' && process.nextTick) {
                nextTick = process.nextTick;
        } else if(MutationObserver = global.MutationObserver || global.WebKitMutationObserver) {
                nextTick = (function(document, MutationObserver, drainQueue) {
                        var el = document.createElement('div');
                        new MutationObserver(drainQueue).observe(el, { attributes: true });

                        return function() {
                                el.setAttribute('x', 'x');
                        };
                }(document, MutationObserver, drainQueue));
        } else {
                try {
                        // vert.x 1.x || 2.x
                        nextTick = cjsRequire('vertx').runOnLoop || cjsRequire('vertx').runOnContext;
                } catch(ignore) {
                        nextTick = function(t) { setTimeout(t, 0); };
                }
        }

        //
        // Capture/polyfill function and array utils
        //

        // Safe function calls
        funcProto = Function.prototype;
        call = funcProto.call;
        fcall = funcProto.bind
                ? call.bind(call)
                : function(f, context) {
                        return f.apply(context, slice.call(arguments, 2));
                };

        // Safe array ops
        arrayProto = [];
        slice = arrayProto.slice;

        // ES5 reduce implementation if native not available
        // See: http://es5.github.com/#x15.4.4.21 as there are many
        // specifics and edge cases.  ES5 dictates that reduce.length === 1
        // This implementation deviates from ES5 spec in the following ways:
        // 1. It does not check if reduceFunc is a Callable
        reduceArray = arrayProto.reduce ||
                function(reduceFunc /*, initialValue */) {
                        /*jshint maxcomplexity: 7*/
                        var arr, args, reduced, len, i;

                        i = 0;
                        arr = Object(this);
                        len = arr.length >>> 0;
                        args = arguments;

                        // If no initialValue, use first item of array (we know length !== 0 here)
                        // and adjust i to start at second item
                        if(args.length <= 1) {
                                // Skip to the first real element in the array
                                for(;;) {
                                        if(i in arr) {
                                                reduced = arr[i++];
                                                break;
                                        }

                                        // If we reached the end of the array without finding any real
                                        // elements, it's a TypeError
                                        if(++i >= len) {
                                                throw new TypeError();
                                        }
                                }
                        } else {
                                // If initialValue provided, use it
                                reduced = args[1];
                        }

                        // Do the actual reduce
                        for(;i < len; ++i) {
                                if(i in arr) {
                                        reduced = reduceFunc(reduced, arr[i], i, arr);
                                }
                        }

                        return reduced;
                };

        function identity(x) {
                return x;
        }

        return when;
});
})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }, this);
</script>
<script>
Benchmark.prototype.setup = function() {
    "use strict";
    function addOne(x) {
        return x + 1;
    }
   
    Q.longStackJumpLimit = 0;
};

Benchmark.prototype.teardown = function() {
    console.log(d);
};
</script>

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
Q
var d = Q.defer();
d.promise.then(addOne);
d.resolve(1);
pending…
when
var d = when.defer();
d.promise.then(addOne);
d.resolve(1);
pending…
P
var d = P.defer();
d.promise.then(addOne);
d.resolve(1);
pending…
Bluebird
var d = Promise.pending();
d.promise.then(addOne);
d.fulfill(1);
pending…
Callback
var d;
function callback(value, cb) {
   cb(value)
}
callback(1, addOne);
 
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