jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
<script src="https://rawgithub.com/petkaantonov/bluebird/master/js/browser/bluebird.js"></script>
<script src="https://rawgithub.com/calvinmetcalf/lie/1.3.0/dist/lie.noConflict.js"></script>
<script>
window.BluebirdPromise = window.Promise.noConflict();
delete window.Promise;
</script>
<script src="https://rsvpjs-builds.s3.amazonaws.com/rsvp-latest.js"></script>
<script src="https://rawgithub.com/calvinmetcalf/catiline/gh-pages/dist/catiline.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/q.js/0.9.6/q.min.js">
</script>
<script>
window.define = function(factory) {
try {
delete window.define;
} catch (e) {
window.define = void 0;
} // IE
window.when = factory();
};
window.define.amd = {};
</script>
<script src="https://rawgithub.com/cujojs/when/master/when.js"></script>
<script src="http://s3.amazonaws.com/es6-promises/promise-0.1.0.min.js"></script>
<script>
// Pimp
/*
* @author Mudit Ameta
* @license https://github.com/zeusdeux/pimp/blob/master/LICENSE MIT
*/
//# sourceMappingURL=pimp.min.map
!function(n){"use strict";function e(n){function r(n){var e;null!==s&&(n.done||(e=s?n.onFulfilled:n.onRejected,e?t(function(){var t;try{t=e(f),n.resolve(t)}catch(r){n.reject(r)}}):s?n.resolve(f):n.reject(f),n.done=!0))}function o(){for(var n in a)r(a[n])}function i(n){if(null===s){if(n)if(l===n)c(new TypeError("Promise cannot resolve to itself. Sorry brah!"));else if(n.constructor&&"Promise"===n.constructor.name)n.then(i,c);else if("function"==typeof n||"object"==typeof n)try{var e=n.then;"function"==typeof e?u(e.bind(n),i,c):(s=!0,f=n)}catch(t){c(t)}else s=!0,f=n;else s=!0,f=n;o()}}function c(n){null===s&&(s=!1,f=n,o())}function u(n,e,t){var r=!1;try{n(function(n){r||(r=!0,e(n))},function(n){r||(r=!0,t(n))})}catch(o){r||(r=!0,t(o))}}var f,s=null,a=[],l=this;if("function"!=typeof n)return new TypeError("Promise constructor requires a function");try{n(i,c)}catch(p){c(p)}this.then=function(n,t){var o,i=new e(function(e,r){o={promise:i,onFulfilled:"function"==typeof n&&n,onRejected:"function"==typeof t&&t,resolve:e,reject:r,done:!1}});return r(o),a.push(o),i},this.inspect=function(){var n={};return null===s?n.state="pending":s?(n.state="fulfilled",n.value=f):(n.state="rejected",n.reason=f),n}}n.exports?n.exports=e:n.Pimp=e;var t;try{process&&process.nextTick?t=process.nextTick:setImmediate&&(t=setImmediate)}catch(r){t=function(n){window.setTimeout(function(){n()},0)}}}("undefined"==typeof module?window:module),function(n){"use strict";function e(n,e){switch(n){case"Pimp.all":case"Pimp.allFail":case"Pimp.race":if(!(e instanceof Array))throw new SyntaxError(n+" needs to be passed an array");if(!e.length)throw new SyntaxError(n+" needs an array of length >= 1");break;case"Pimp.denodeify":if(!(e instanceof Function))throw new SyntaxError(n+" needs to be passed a function to promisify")}return!0}var t;t="[object Window]"===n.toString()&&"undefined"==typeof require?n.Pimp:require("./pimp"),n.exports?n.exports=t:n.Pimp=t,t.prototype.catch=function(n){return this.then(function(n){return n},n)},t.resolve=function(n){return new t(function(e){e(n)})},t.reject=function(n){return new t(function(e,t){t(n)})},t.cast=function(n){return n instanceof t&&n.then?n:t.resolve(n)},t.all=function(n){return e("Pimp.all",n),new t(function(e,r){var o=0,i=[];for(var c in n)n.hasOwnProperty(c)&&(n[c].then||(n[c]=t.cast(n[c])),n[c].then(function(t){o++,i.push(t),n.length===o&&e(i)},function(n){r(n)}))})},t.allFail=function(n){return e("Pimp.allFail",n),new t(function(e,r){var o=0,i=[];for(var c in n)n.hasOwnProperty(c)&&(n[c].then||(n[c]=t.cast(n[c])),n[c].then(function(n){r(n)},function(t){o++,i.push(t),n.length===o&&e(i)}))})},t.race=function(n){return e("Pimp.race",n),new t(function(e,r){for(var o in n)n.hasOwnProperty(o)&&(n[o].then||(n[o]=t.cast(n[o])),n[o].then(function(n){e(n)},function(n){r(n)}))})},t.deferred=function(){var n={};return n.promise=new t(function(e,t){n.resolve=e,n.reject=t}),n.inspect=n.promise.inspect,n},t.denodeify=function(n){return e("Pimp.denodeify",n),function(){var e=t.deferred(),r=function(n,t){n?e.reject(n):e.resolve(t)};return[].push.call(arguments,r),n.apply(this,arguments),e.promise}}}("undefined"==typeof module?window:module);
</script>
<script>
// Kew
function Promise(onSuccess, onFail) {
this.promise = this
this._isPromise = true
this._successFn = onSuccess
this._failFn = onFail
this._scope = this
this._boundArgs = null
this._hasContext = false
this._nextContext = undefined
this._currentContext = undefined
}
/**
* Keep track of the number of promises that are rejected along side
* the number of rejected promises we call _failFn on so we can look
* for leaked rejections.
*/
function PromiseStats() {
this.errorsEmitted = 0
this.errorsHandled = 0
}
var stats = new PromiseStats()
Promise.prototype._handleError = function () {
if (!this._errorHandled) {
stats.errorsHandled++
this._errorHandled = true
}
}
/**
* Specify that the current promise should have a specified context
* @param {*} context context
* @private
*/
Promise.prototype._useContext = function (context) {
this._nextContext = this._currentContext = context
this._hasContext = true
return this
}
Promise.prototype.clearContext = function () {
this._hasContext = false
this._nextContext = undefined
return this
}
/**
* Set the context for all promise handlers to follow
*
* NOTE(dpup): This should be considered deprecated. It does not do what most
* people would expect. The context will be passed as a second argument to all
* subsequent callbacks.
*
* @param {*} context An arbitrary context
*/
Promise.prototype.setContext = function (context) {
this._nextContext = context
this._hasContext = true
return this
}
/**
* Get the context for a promise
* @return {*} the context set by setContext
*/
Promise.prototype.getContext = function () {
return this._nextContext
}
/**
* Resolve this promise with a specified value
*
* @param {*=} data
*/
Promise.prototype.resolve = function (data) {
if (this._error || this._hasData) throw new Error("Unable to resolve or reject the same promise twice")
var i
if (data && isPromise(data)) {
this._child = data
if (this._promises) {
for (i = 0; i < this._promises.length; i += 1) {
data._chainPromise(this._promises[i])
}
delete this._promises
}
if (this._onComplete) {
for (i = 0; i < this._onComplete.length; i+= 1) {
data.fin(this._onComplete[i])
}
delete this._onComplete
}
} else if (data && isPromiseLike(data)) {
data.then(
function(data) { this.resolve(data) }.bind(this),
function(err) { this.reject(err) }.bind(this)
)
} else {
this._hasData = true
this._data = data
if (this._onComplete) {
for (i = 0; i < this._onComplete.length; i++) {
this._onComplete[i]()
}
}
if (this._promises) {
for (i = 0; i < this._promises.length; i += 1) {
this._promises[i]._withInput(data)
}
delete this._promises
}
}
}
/**
* Reject this promise with an error
*
* @param {!Error} e
*/
Promise.prototype.reject = function (e) {
if (this._error || this._hasData) throw new Error("Unable to resolve or reject the same promise twice")
var i
this._error = e
stats.errorsEmitted++
if (this._ended) {
this._handleError()
process.nextTick(function onPromiseThrow() {
throw e
})
}
if (this._onComplete) {
for (i = 0; i < this._onComplete.length; i++) {
this._onComplete[i]()
}
}
if (this._promises) {
this._handleError()
for (i = 0; i < this._promises.length; i += 1) {
this._promises[i]._withError(e)
}
delete this._promises
}
}
/**
* Provide a callback to be called whenever this promise successfully
* resolves. Allows for an optional second callback to handle the failure
* case.
*
* @param {?function(this:void, T, ?): RESULT|undefined} onSuccess
* @param {?function(this:void, !Error, ?): RESULT=} onFail
* @return {!Promise.<RESULT>} returns a new promise with the output of the onSuccess or
* onFail handler
* @template RESULT
*/
Promise.prototype.then = function (onSuccess, onFail) {
var promise = new Promise(onSuccess, onFail)
if (this._nextContext) promise._useContext(this._nextContext)
if (this._child) this._child._chainPromise(promise)
else this._chainPromise(promise)
return promise
}
/**
* Provide a callback to be called whenever this promise successfully
* resolves. The callback will be executed in the context of the provided scope.
*
* @param {function(this:SCOPE, T, ?): RESULT} onSuccess
* @param {SCOPE} scope Object whose context callback will be executed in.
* @param {...*} var_args Additional arguments to be passed to the promise callback.
* @return {!Promise.<RESULT>} returns a new promise with the output of the onSuccess
* @template SCOPE, RESULT
*/
Promise.prototype.thenBound = function (onSuccess, scope, var_args) {
var promise = new Promise(onSuccess)
if (this._nextContext) promise._useContext(this._nextContext)
promise._scope = scope
if (arguments.length > 2) {
promise._boundArgs = Array.prototype.slice.call(arguments, 2)
}
// Chaining must happen after setting args and scope since it may fire callback.
if (this._child) this._child._chainPromise(promise)
else this._chainPromise(promise)
return promise
}
/**
* Provide a callback to be called whenever this promise is rejected
*
* @param {function(this:void, !Error, ?)} onFail
* @return {!Promise.<T>} returns a new promise with the output of the onFail handler
*/
Promise.prototype.fail = function (onFail) {
return this.then(null, onFail)
}
/**
* Provide a callback to be called whenever this promise is rejected.
* The callback will be executed in the context of the provided scope.
*
* @param {function(this:SCOPE, Error, ?)} onFail
* @param {SCOPE} scope Object whose context callback will be executed in.
* @param {...?} var_args
* @return {!Promise.<T>} returns a new promise with the output of the onSuccess
* @template SCOPE
*/
Promise.prototype.failBound = function (onFail, scope, var_args) {
var promise = new Promise(null, onFail)
if (this._nextContext) promise._useContext(this._nextContext)
promise._scope = scope
if (arguments.length > 2) {
promise._boundArgs = Array.prototype.slice.call(arguments, 2)
}
// Chaining must happen after setting args and scope since it may fire callback.
if (this._child) this._child._chainPromise(promise)
else this._chainPromise(promise)
return promise
}
/**
* Provide a callback to be called whenever this promise is either resolved
* or rejected.
*
* @param {function()} onComplete
* @return {!Promise.<T>} returns the current promise
*/
Promise.prototype.fin = function (onComplete) {
if (this._hasData || this._error) {
onComplete()
return this
}
if (this._child) {
this._child.fin(onComplete)
} else {
if (!this._onComplete) this._onComplete = [onComplete]
else this._onComplete.push(onComplete)
}
return this
}
/**
* Mark this promise as "ended". If the promise is rejected, this will throw an
* error in whatever scope it happens to be in
*
* @return {!Promise.<T>} returns the current promise
* @deprecated Prefer done(), because it's consistent with Q.
*/
Promise.prototype.end = function () {
this._end()
return this
}
/**
* Mark this promise as "ended".
* @private
*/
Promise.prototype._end = function () {
if (this._error) {
this._handleError()
throw this._error
}
this._ended = true
return this
}
/**
* Close the promise. Any errors after this completes will be thrown to the global handler.
*
* @param {?function(this:void, T, ?)=} onSuccess a function to handle successful
* resolution of this promise
* @param {?function(this:void, !Error, ?)=} onFailure a function to handle failed
* resolution of this promise
* @return {void}
*/
Promise.prototype.done = function (onSuccess, onFailure) {
var self = this
if (onSuccess || onFailure) {
self = self.then(onSuccess, onFailure)
}
self._end()
}
/**
* Return a new promise that behaves the same as the current promise except
* that it will be rejected if the current promise does not get fulfilled
* after a certain amount of time.
*
* @param {number} timeoutMs The timeout threshold in msec
* @param {string=} timeoutMsg error message
* @return {!Promise.<T>} a new promise with timeout
*/
Promise.prototype.timeout = function (timeoutMs, timeoutMsg) {
var deferred = new Promise()
var isTimeout = false
var timeout = setTimeout(function() {
deferred.reject(new Error(timeoutMsg || 'Promise timeout after ' + timeoutMs + ' ms.'))
isTimeout = true
}, timeoutMs)
this.then(function (data) {
if (!isTimeout) {
clearTimeout(timeout)
deferred.resolve(data)
}
},
function (err) {
if (!isTimeout) {
clearTimeout(timeout)
deferred.reject(err)
}
})
return deferred.promise
}
/**
* Attempt to resolve this promise with the specified input
*
* @param {*} data the input
*/
Promise.prototype._withInput = function (data) {
if (this._successFn) {
try {
this.resolve(this._call(this._successFn, [data, this._currentContext]))
} catch (e) {
this.reject(e)
}
} else this.resolve(data)
// context is no longer needed
delete this._currentContext
}
/**
* Attempt to reject this promise with the specified error
*
* @param {!Error} e
* @private
*/
Promise.prototype._withError = function (e) {
if (this._failFn) {
try {
this.resolve(this._call(this._failFn, [e, this._currentContext]))
} catch (thrown) {
this.reject(thrown)
}
} else this.reject(e)
// context is no longer needed
delete this._currentContext
}
/**
* Calls a function in the correct scope, and includes bound arguments.
* @param {Function} fn
* @param {Array} args
* @return {*}
* @private
*/
Promise.prototype._call = function (fn, args) {
if (this._boundArgs) {
args = this._boundArgs.concat(args)
}
return fn.apply(this._scope, args)
}
/**
* Chain a promise to the current promise
*
* @param {!Promise} promise the promise to chain
* @private
*/
Promise.prototype._chainPromise = function (promise) {
var i
if (this._hasContext) promise._useContext(this._nextContext)
if (this._child) {
this._child._chainPromise(promise)
} else if (this._hasData) {
promise._withInput(this._data)
} else if (this._error) {
// We can't rely on _withError() because it's called on the chained promises
// and we need to use the source's _errorHandled state
this._handleError()
promise._withError(this._error)
} else if (!this._promises) {
this._promises = [promise]
} else {
this._promises.push(promise)
}
}
/**
* Utility function used for creating a node-style resolver
* for deferreds
*
* @param {!Promise} deferred a promise that looks like a deferred
* @param {Error=} err an optional error
* @param {*=} data optional data
*/
function resolver(deferred, err, data) {
if (err) deferred.reject(err)
else deferred.resolve(data)
}
/**
* Creates a node-style resolver for a deferred by wrapping
* resolver()
*
* @return {function(?Error, *)} node-style callback
*/
Promise.prototype.makeNodeResolver = function () {
return resolver.bind(null, this)
}
/**
* Return true iff the given object is a promise of this library.
*
* Because kew's API is slightly different than other promise libraries,
* it's important that we have a test for its promise type. If you want
* to test for a more general A+ promise, you should do a cap test for
* the features you want.
*
* @param {*} obj The object to test
* @return {boolean} Whether the object is a promise
*/
function isPromise(obj) {
return !!obj._isPromise
}
/**
* Return true iff the given object is a promise-like object, e.g. appears to
* implement Promises/A+ specification
*
* @param {*} obj The object to test
* @return {boolean} Whether the object is a promise-like object
*/
function isPromiseLike(obj) {
return typeof obj === 'object' && typeof obj.then === 'function'
}
/**
* Static function which creates and resolves a promise immediately
*
* @param {T} data data to resolve the promise with
* @return {!Promise.<T>}
* @template T
*/
function resolve(data) {
var promise = new Promise()
promise.resolve(data)
return promise
}
/**
* Static function which creates and rejects a promise immediately
*
* @param {!Error} e error to reject the promise with
* @return {!Promise}
*/
function reject(e) {
var promise = new Promise()
promise.reject(e)
return promise
}
/**
* Replace an element in an array with a new value. Used by .all() to
* call from .then()
*
* @param {!Array} arr
* @param {number} idx
* @param {*} val
* @return {*} the val that's being injected into the array
*/
function replaceEl(arr, idx, val) {
arr[idx] = val
return val
}
/**
* Replace an element in an array as it is resolved with its value.
* Used by .allSettled().
*
* @param {!Array} arr
* @param {number} idx
* @param {*} value The value from a resolved promise.
* @return {*} the data that's being passed in
*/
function replaceElFulfilled(arr, idx, value) {
arr[idx] = {
state: 'fulfilled',
value: value
}
return value
}
/**
* Replace an element in an array as it is rejected with the reason.
* Used by .allSettled().
*
* @param {!Array} arr
* @param {number} idx
* @param {*} reason The reason why the original promise is rejected
* @return {*} the data that's being passed in
*/
function replaceElRejected(arr, idx, reason) {
arr[idx] = {
state: 'rejected',
reason: reason
}
return reason
}
/**
* Takes in an array of promises or literals and returns a promise which returns
* an array of values when all have resolved. If any fail, the promise fails.
*
* @param {!Array.<!Promise>} promises
* @return {!Promise.<!Array>}
*/
function all(promises) {
if (arguments.length != 1 || !Array.isArray(promises)) {
promises = Array.prototype.slice.call(arguments, 0)
}
if (!promises.length) return resolve([])
var outputs = []
var finished = false
var promise = new Promise()
var counter = promises.length
for (var i = 0; i < promises.length; i += 1) {
if (!promises[i] || !isPromiseLike(promises[i])) {
outputs[i] = promises[i]
counter -= 1
} else {
promises[i].then(replaceEl.bind(null, outputs, i))
.then(function decrementAllCounter() {
counter--
if (!finished && counter === 0) {
finished = true
promise.resolve(outputs)
}
}, function onAllError(e) {
if (!finished) {
finished = true
promise.reject(e)
}
})
}
}
if (counter === 0 && !finished) {
finished = true
promise.resolve(outputs)
}
return promise
}
/**
* Takes in an array of promises or values and returns a promise that is
* fulfilled with an array of state objects when all have resolved or
* rejected. If a promise is resolved, its corresponding state object is
* {state: 'fulfilled', value: Object}; whereas if a promise is rejected, its
* corresponding state object is {state: 'rejected', reason: Object}.
*
* @param {!Array} promises or values
* @return {!Promise.<!Array>} Promise fulfilled with state objects for each input
*/
function allSettled(promises) {
if (!Array.isArray(promises)) {
throw Error('The input to "allSettled()" should be an array of Promise or values')
}
if (!promises.length) return resolve([])
var outputs = []
var promise = new Promise()
var counter = promises.length
for (var i = 0; i < promises.length; i += 1) {
if (!promises[i] || !isPromiseLike(promises[i])) {
replaceElFulfilled(outputs, i, promises[i])
if ((--counter) === 0) promise.resolve(outputs)
} else {
promises[i]
.then(replaceElFulfilled.bind(null, outputs, i), replaceElRejected.bind(null, outputs, i))
.then(function () {
if ((--counter) === 0) promise.resolve(outputs)
})
}
}
return promise
}
/**
* Create a new Promise which looks like a deferred
*
* @return {!Promise}
*/
function defer() {
return new Promise()
}
/**
* Return a promise which will wait a specified number of ms to resolve
*
* @param {*} delayMsOrVal A delay (in ms) if this takes one argument, or ther
* return value if it takes two.
* @param {number=} opt_delayMs
* @return {!Promise}
*/
function delay(delayMsOrVal, opt_delayMs) {
var returnVal = undefined
var delayMs = delayMsOrVal
if (typeof opt_delayMs != 'undefined') {
delayMs = opt_delayMs
returnVal = delayMsOrVal
}
if (typeof delayMs != 'number') {
throw new Error('Bad delay value ' + delayMs)
}
var defer = new Promise()
setTimeout(function onDelay() {
defer.resolve(returnVal)
}, delayMs)
return defer
}
/**
* Returns a promise that has the same result as `this`, but fulfilled
* after at least ms milliseconds
* @param {number} ms
*/
Promise.prototype.delay = function (ms) {
return this.then(function (val) {
return delay(val, ms)
})
}
/**
* Return a promise which will evaluate the function fn in a future turn with
* the provided args
*
* @param {function(...)} fn
* @param {...*} var_args a variable number of arguments
* @return {!Promise}
*/
function fcall(fn, var_args) {
var rootArgs = Array.prototype.slice.call(arguments, 1)
var defer = new Promise()
process.nextTick(function onNextTick() {
try {
defer.resolve(fn.apply(undefined, rootArgs))
} catch (e) {
defer.reject(e)
}
})
return defer
}
/**
* Returns a promise that will be invoked with the result of a node style
* callback. All args to fn should be given except for the final callback arg
*
* @param {function(...)} fn
* @param {...*} var_args a variable number of arguments
* @return {!Promise}
*/
function nfcall(fn, var_args) {
// Insert an undefined argument for scope and let bindPromise() do the work.
var args = Array.prototype.slice.call(arguments, 0)
args.splice(1, 0, undefined)
return bindPromise.apply(undefined, args)()
}
/**
* Binds a function to a scope with an optional number of curried arguments. Attaches
* a node style callback as the last argument and returns a promise
*
* @param {function(...)} fn
* @param {Object} scope
* @param {...*} var_args a variable number of arguments
* @return {function(...)}: !Promise}
*/
function bindPromise(fn, scope, var_args) {
var rootArgs = Array.prototype.slice.call(arguments, 2)
return function onBoundPromise(var_args) {
var defer = new Promise()
try {
fn.apply(scope, rootArgs.concat(Array.prototype.slice.call(arguments, 0), defer.makeNodeResolver()))
} catch (e) {
defer.reject(e)
}
return defer
}
}
K = {
all: all
, bindPromise: bindPromise
, defer: defer
, delay: delay
, fcall: fcall
, isPromise: isPromise
, isPromiseLike: isPromiseLike
, nfcall: nfcall
, resolve: resolve
, reject: reject
, stats: stats
, allSettled: allSettled
, Promise: Promise
};
</script>
<script>
(function UMD(name,context,definition){
// special form of UMD for polyfilling across evironments
context[name] = context[name] || definition();
if (typeof module != "undefined" && module.exports) { module.exports = context[name]; }
else if (typeof define == "function" && define.amd) { define(function $AMD$(){ return context[name]; }); }
})("PromiseNPO",typeof global != "undefined" ? global : this,function DEF(){
/*jshint validthis:true */
"use strict";
var cycle, scheduling_queue, ToString = Object.prototype.toString,
timer = (typeof setImmediate != "undefined") ?
function timer(fn) { return setImmediate(fn); } :
setTimeout,
builtInProp = Object.defineProperty ?
function builtInProp(obj,name,val,config) {
return Object.defineProperty(obj,name,{
value: val,
writable: true,
configurable: config !== false
});
} :
function builtInProp(obj,name,val) {
obj[name] = val;
return obj;
}
;
// Note: using a queue instead of array for efficiency
scheduling_queue = (function Queue() {
var first, last, item;
function Item(fn,self) {
this.fn = fn;
this.self = self;
this.next = void 0;
}
return {
add: function add(fn,self) {
item = new Item(fn,self);
if (last) {
last.next = item;
}
else {
first = item;
}
last = item;
item = void 0;
},
drain: function drain() {
var f = first;
first = last = cycle = void 0;
while (f) {
f.fn.call(f.self);
f = f.next;
}
}
};
})();
function schedule(fn,self) {
scheduling_queue.add(fn,self);
if (!cycle) {
cycle = timer(scheduling_queue.drain);
}
}
// promise duck typing
function isThenable(o) {
var _then, o_type = typeof o;
if (o != null &&
(
o_type == "object" || o_type == "function"
)
) {
_then = o.then;
}
return typeof _then == "function" ? _then : false;
}
function notify() {
for (var i=0; i<this.chain.length; i++) {
notifyIsolated(
this,
(this.state === 1) ? this.chain[i].success : this.chain[i].failure,
this.chain[i]
);
}
this.chain.length = 0;
}
// NOTE: This is a separate function to isolate
// the `try..catch` so that other code can be
// optimized better
function notifyIsolated(self,cb,chain) {
var ret, _then;
try {
if (cb === false) {
chain.reject(self.msg);
}
else {
if (cb === true) {
ret = self.msg;
}
else {
ret = cb.call(void 0,self.msg);
}
if (ret === chain.promise) {
chain.reject(TypeError("Promise-chain cycle"));
}
else if (_then = isThenable(ret)) {
_then.call(ret,chain.resolve,chain.reject);
}
else {
chain.resolve(ret);
}
}
}
catch (err) {
chain.reject(err);
}
}
function resolve(msg) {
var _then, def_wrapper, self = this;
// already triggered?
if (self.triggered) { return; }
self.triggered = true;
// unwrap
if (self.def) {
self = self.def;
}
try {
if (_then = isThenable(msg)) {
def_wrapper = new MakeDefWrapper(self);
_then.call(msg,
function $resolve$(){ resolve.apply(def_wrapper,arguments); },
function $reject$(){ reject.apply(def_wrapper,arguments); }
);
}
else {
self.msg = msg;
self.state = 1;
if (self.chain.length > 0) {
schedule(notify,self);
}
}
}
catch (err) {
reject.call(def_wrapper || (new MakeDefWrapper(self)),err);
}
}
function reject(msg) {
var self = this;
// already triggered?
if (self.triggered) { return; }
self.triggered = true;
// unwrap
if (self.def) {
self = self.def;
}
self.msg = msg;
self.state = 2;
if (self.chain.length > 0) {
schedule(notify,self);
}
}
function iteratePromises(Constructor,arr,resolver,rejecter) {
for (var idx=0; idx<arr.length; idx++) {
(function IIFE(idx){
Constructor.resolve(arr[idx])
.then(
function $resolver$(msg){
resolver(idx,msg);
},
rejecter
);
})(idx);
}
}
function MakeDefWrapper(self) {
this.def = self;
this.triggered = false;
}
function MakeDef(self) {
this.promise = self;
this.state = 0;
this.triggered = false;
this.chain = [];
this.msg = void 0;
}
function Promise(executor) {
if (typeof executor != "function") {
throw TypeError("Not a function");
}
if (this.__NPO__ !== 0) {
throw TypeError("Not a promise");
}
// instance shadowing the inherited "brand"
// to signal an already "initialized" promise
this.__NPO__ = 1;
var def = new MakeDef(this);
this["then"] = function then(success,failure) {
var o = {
success: typeof success == "function" ? success : true,
failure: typeof failure == "function" ? failure : false
};
// Note: `then(..)` itself can be borrowed to be used against
// a different promise constructor for making the chained promise,
// by substituting a different `this` binding.
o.promise = new this.constructor(function extractChain(resolve,reject) {
if (typeof resolve != "function" || typeof reject != "function") {
throw TypeError("Not a function");
}
o.resolve = resolve;
o.reject = reject;
});
def.chain.push(o);
if (def.state !== 0) {
schedule(notify,def);
}
return o.promise;
};
this["catch"] = function $catch$(failure) {
return this.then(void 0,failure);
};
try {
executor.call(
void 0,
function publicResolve(msg){
resolve.call(def,msg);
},
function publicReject(msg) {
reject.call(def,msg);
}
);
}
catch (err) {
reject.call(def,err);
}
}
var PromisePrototype = builtInProp({},"constructor",Promise,
/*configurable=*/false
);
builtInProp(
Promise,"prototype",PromisePrototype,
/*configurable=*/false
);
// built-in "brand" to signal an "uninitialized" promise
builtInProp(PromisePrototype,"__NPO__",0,
/*configurable=*/false
);
builtInProp(Promise,"resolve",function Promise$resolve(msg) {
var Constructor = this;
// spec mandated checks
// note: best "isPromise" check that's practical for now
if (msg && typeof msg == "object" && msg.__NPO__ === 1) {
return msg;
}
return new Constructor(function executor(resolve,reject){
if (typeof resolve != "function" || typeof reject != "function") {
throw TypeError("Not a function");
}
resolve(msg);
});
});
builtInProp(Promise,"reject",function Promise$reject(msg) {
return new this(function executor(resolve,reject){
if (typeof resolve != "function" || typeof reject != "function") {
throw TypeError("Not a function");
}
reject(msg);
});
});
builtInProp(Promise,"all",function Promise$all(arr) {
var Constructor = this;
// spec mandated checks
if (ToString.call(arr) != "[object Array]") {
return Constructor.reject(TypeError("Not an array"));
}
if (arr.length === 0) {
return Constructor.resolve([]);
}
return new Constructor(function executor(resolve,reject){
if (typeof resolve != "function" || typeof reject != "function") {
throw TypeError("Not a function");
}
var len = arr.length, msgs = Array(len), count = 0;
iteratePromises(Constructor,arr,function resolver(idx,msg) {
msgs[idx] = msg;
if (++count === len) {
resolve(msgs);
}
},reject);
});
});
builtInProp(Promise,"race",function Promise$race(arr) {
var Constructor = this;
// spec mandated checks
if (ToString.call(arr) != "[object Array]") {
return Constructor.reject(TypeError("Not an array"));
}
return new Constructor(function executor(resolve,reject){
if (typeof resolve != "function" || typeof reject != "function") {
throw TypeError("Not a function");
}
iteratePromises(Constructor,arr,function resolver(idx,msg){
resolve(msg);
},reject);
});
});
return Promise;
});
</script>
<script src="https://rawgit.com/cujojs/when/master/when.js"></script>
Ready to run.
Test | Ops/sec | |
---|---|---|
when |
| ready |
RSVP |
| ready |
q |
| ready |
catiline |
| ready |
bluebird |
| ready |
Pimp |
| ready |
ES6 Promise polyfill |
| ready |
Kew |
| ready |
lie |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.