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
This is a comparison of different promise libraries, performing the most basic tasks of creating a promise, adding a then handler and then resolving the promise.
Recent benchmarks deliberately cripple bluebird but didn't force the same method on other libraries.
*Added ES6 Promise polyfill *Added kew *Added MyDeferred
<script src="http://sk.orion.eclipse.org:8080/orion/Deferred.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="https://rawgithub.com/cho45/jsdeferred/master/jsdeferred.js"></script>
<script src="https://rawgithub.com/petkaantonov/bluebird/master/js/browser/bluebird.js"></script>
<script>
window.BluebirdPromise = window.Promise.noConflict();
delete window.Promise;
</script>
<script src="https://rawgithub.com/calvinmetcalf/lie/master/dist/lie.noConflict.js"></script><script src="http://rsvpjs-builds.s3.amazonaws.com/rsvp-latest.js"></script>
<script src="https://rawgithub.com/calvinmetcalf/catiline/master/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>
var worker = cw({
init:function(self){
self.on('ping',function(d){
self.fire('pong',d);
});
}
});
</script>
<script src="http://yui.yahooapis.com/3.14.1/build/yui/yui-min.js"></script>
<script>
YUI().use('promise', function (Y) {
window.Y = Y;
});
</script>
<script src="http://s3.amazonaws.com/es6-promises/promise-0.1.1.min.js"></script>
<script>
window.kew = (function(){
/** @typedef {function(?, ?)} */
var OnSuccessCallbackType;
/** @typedef {function(!Error, ?)} */
var OnFailCallbackType;
/**
* An object representing a "promise" for a future value
*
* @param {?OnSuccessCallbackType=} onSuccess a function to handle successful
* resolution of this promise
* @param {OnFailCallbackType=} onFail a function to handle failed
* resolution of this promise
* @constructor
*/
function Promise(onSuccess, onFail) {
this.promise = this
this._isPromise = true
this._successFn = onSuccess
this._failFn = onFail
this._hasContext = false
this._nextContext = undefined
this._currentContext = undefined
}
/**
* 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
* @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
if (this._ended) {
process.nextTick(function onPromiseThrow() {
throw e
})
}
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]._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 {?OnSuccessCallbackType} onSuccess
* @param {OnFailCallbackType=} onFail
* @return {!Promise} returns a new promise with the output of the onSuccess or
* onFail handler
*/
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 is rejected
*
* @param {OnFailCallbackType} onFail
* @return {!Promise} 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 either resolved
* or rejected.
*
* @param {function()} onComplete
* @return {!Promise} 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} returns the current promise
*/
Promise.prototype.end = function () {
if (this._error) {
throw this._error
}
this._ended = true
return this
}
/**
* 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
* @returns 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._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._failFn(e, this._currentContext))
} catch (thrown) {
this.reject(thrown)
}
} else this.reject(e)
// context is no longer needed
delete this._currentContext
}
/**
* 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) {
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 {*} data data to resolve the promise with
* @return {!Promise}
*/
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}
*/
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 literals and returns a promise which returns
* an array of values when all have resolved or rejected.
*
* @param {!Array.<!Promise>} promises
* @return {!Array.<Object>} The state of the promises. 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}
*/
function allSettled(promises) {
if (!Array.isArray(promises)) {
throw Error('The input to "allSettled()" should be an array of Promise')
}
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 {number} delayMs
* @param {*} returnVal
* @return {!Promise} returns returnVal
*/
function delay(delayMs, returnVal) {
var defer = new Promise()
setTimeout(function onDelay() {
defer.resolve(returnVal)
}, delayMs)
return defer
}
/**
* 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() {
defer.resolve(fn.apply(undefined, rootArgs))
})
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()
fn.apply(scope, rootArgs.concat(Array.prototype.slice.call(arguments, 0), defer.makeNodeResolver()))
return defer
}
}
var module = {};
module.exports = {
all: all
, bindPromise: bindPromise
, defer: defer
, delay: delay
, fcall: fcall
, isPromise: isPromise
, isPromiseLike: isPromiseLike
, nfcall: nfcall
, resolve: resolve
, reject: reject
, allSettled: allSettled
}
return module.exports;
}())
/**
* @author RubaXa <trash@rubaxa.org>
* @license MIT
*/
;(function (){
function _then(promise, method, callback){
return function (){
var args = arguments;
if( typeof callback === 'function' ){
var retVal = callback.apply(promise, args);
if( retVal && typeof retVal.then === 'function' ){
retVal.done(promise.resolve).fail(promise.reject);
return;
}
}
promise[method].apply(promise, args);
};
}
/**
* Fastest Deferred.
* @returns {Deferred}
*/
var Deferred = function (){
var
_args,
_doneFn = [],
_failFn = [],
dfd = {
done: function (fn){
_doneFn.push(fn);
return dfd;
},
fail: function (fn){
_failFn.push(fn);
return dfd;
},
then: function (doneFn, failFn){
var promise = Deferred();
dfd
.done(_then(promise, 'resolve', doneFn))
.fail(_then(promise, 'reject', failFn))
;
return promise;
},
always: function (fn){
return dfd.done(fn).fail(fn);
},
resolve: _setState(true),
reject: _setState(false)
}
;
function _setState(state){
return function (){
_args = arguments;
dfd.done =
dfd.fail =
dfd.resolve =
dfd.reject = function (){
return dfd;
};
dfd[state ? 'done' : 'fail'] = function (fn){
if( typeof fn === 'function' ){
fn.apply(dfd, _args);
}
return dfd;
};
var
fn
, fns = state ? _doneFn : _failFn
, i = 0, n = fns.length
;
for( ; i < n; i++ ){
fn = fns[i];
if( typeof fn === 'function' ){
fn.apply(dfd, _args);
}
}
fns = _doneFn = _failFn = null;
return dfd;
}
}
return dfd;
};
/**
* @param {Array} args
* @returns {defer|*}
*/
Deferred.when = function (args){
var
dfd = Deferred()
, d
, i = args.length
, remain = i || 1
, _doneFn = function (){
if( --remain === 0 ){
dfd.resolve();
}
}
;
if( i === 0 ){
_doneFn();
}
else {
while( i-- ){
d = args[i];
if( d && d.then ){
d.then(_doneFn, dfd.reject);
}
}
}
return dfd;
};
// exports
window.MyDeferred = Deferred;
})();
window.MyPromise = function () {
var global = Function('return this')();
var isObject = function (arg) {
return typeof arg === 'object' &&
arg !== null;
};
var isFunction = function (arg) {
return typeof arg === 'function';
};
var isObjectOrFunction = function (arg) {
return isObject(arg) || isFunction(arg);
};
var isNative = function (target) {
return typeof target === 'object' ||
(target + '').slice(-17) === '{ [native code] }';
};
var final_ = function (initialiser, value) {
return function () {
if (initialiser !== null) {
value = initialiser(value);
initialiser = null;
}
return value;
};
};
var scheduleMicrotask = function () {
var finalSchedule = function () {
var queue = [];
function flushQueue() {
var tasks = queue;
queue = [];
for (var i = 0; i < tasks.length; i++) {
tasks[i]();
}
}
function usePromise() {
return null;
if (!isNative(global.Promise)) {
return null;
}
var fulfilled = new Promise(function (resolve) {
resolve();
});
return function () {
fulfilled.then(flushQueue);
};
}
function useMutationObserver() {
if (!isNative(global.MutationObserver)) {
return null;
}
var iterations = 0;
var observer = new MutationObserver(flushQueue);
var node = document.createTextNode('');
observer.observe(node, { characterData: true });
return function() {
node.data = (iterations = ++iterations % 2);
};
}
function useSetImmediate() {
if (!isNative(global.setImmediate)) {
return null;
}
var immediateId;
var timerId;
function raceFlush() {
clearTimeout(timerId);
clearImmediate(immediateId);
flushQueue();
}
return function () {
immediateId = setImmediate(raceFlush);
timerId = setTimeout(raceFlush);
};
}
function useSetTimeout() {
return function () {
setTimeout(flushQueue);
};
}
var scheduleFlush = usePromise() ||
useMutationObserver() ||
useSetImmediate() ||
useSetTimeout();
return function (callback) {
queue.push(callback);
if (queue.length <= 1) {
scheduleFlush();
}
};
}();
return function (callback) {
finalSchedule(callback);
};
}();
return function () {
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise(resolver) {
this._state = PENDING;
this._value = [];
var promise = this;
try {
resolver(function (value) {
resolve(promise, value);
}, function (reason) {
reject(promise, reason);
});
} catch (ex) {
reject(promise, ex);
}
}
function Promise2() {
this._state = PENDING;
this._value = [];
}
Promise2.prototype = Promise.prototype;
Promise.prototype._state = PENDING;
Promise.prototype._value = '';
function invokeCallback(settled, value, callback, promise) {
if (isFunction(callback)) {
try {
resolve(promise, callback(value));
} catch (ex) {
reject(promise, ex);
}
} else {
publish(promise, settled, value);
}
}
function publish(promise, settled, value) {
var subscribers = promise._value;
promise._state = settled;
promise._value = value;
for (var i = 0; i < subscribers.length; i += 3) {
invokeCallback(
settled,
value,
subscribers[i + settled],
subscribers[i]);
}
}
function schedulePublish(promise, state, value) {
scheduleMicrotask(function () {
publish(promise, state, value);
});
}
function isThenable(value) {
return isObjectOrFunction(value) &&
isFunction(value.then);
}
function chainThenable(thenable, promise) {
try {
thenable.then(function (value) {
resolve(promise, value);
}, function (reason) {
reject(promise, reason);
});
} catch (ex) {
reject(promise, ex);
}
}
function resolve(promise, value) {
if (value !== this && isThenable(value)) {
chainThenable(value, promise);
} else {
schedulePublish(promise, FULFILLED, value);
}
}
function reject(promise, reason) {
schedulePublish(promise, REJECTED, reason);
}
Promise.prototype.then = function (onFulfilled, onRejected) {
var childPromise = new Promise2();
if (this._state <= PENDING) {
this._value.push(childPromise);
this._value.push(onFulfilled);
this._value.push(onRejected);
} else {
var callback = (this._state >= REJECTED) ?
onRejected : onFulfilled;
if (!isFunction(callback)) {
publish(childPromise, this._state, this._value);
} else {
var promise = this;
scheduleMicrotask(function () {
invokeCallback(
promise._state,
promise._value,
callback,
childPromise);
});
}
}
return childPromise;
};
window.MyPromise2 = Promise2;
window.resolveMyPromise = resolve;
return Promise;
}();
}();
</script>
/**
* @module vow
* @author Filatov Dmitry <dfilatov@yandex-team.ru>
* @version 0.4.8
* @license
* Dual licensed under the MIT and GPL licenses:
* * http://www.opensource.org/licenses/mit-license.php
* * http://www.gnu.org/licenses/gpl.html
*/
(function(e) {
var t, n = function() {
var t = [],
n = function(e) {
return t.push(e) === 1
}, r = function() {
var e = t,
n = 0,
r = t.length;
t = [];
while (n < r) e[n++]()
};
if (typeof setImmediate == "function") return function(e) {
n(e) && setImmediate(r)
};
if (typeof process == "object" && process.nextTick) return function(e) {
n(e) && process.nextTick(r)
};
if (e.postMessage) {
var i = !0;
if (e.attachEvent) {
var s = function() {
i = !1
};
e.attachEvent("onmessage", s), e.postMessage("__checkAsync", "*"), e.detachEvent("onmessage", s)
}
if (i) {
var o = "__promise" + +(new Date),
u = function(e) {
e.data === o && (e.stopPropagation && e.stopPropagation(), r())
};
return e.addEventListener ? e.addEventListener("message", u, !0) : e.attachEvent("onmessage", u),
function(t) {
n(t) && e.postMessage(o, "*")
}
}
}
var a = e.document;
if ("onreadystatechange" in a.createElement("script")) {
var f = function() {
var e = a.createElement("script");
e.onreadystatechange = function() {
e.parentNode.removeChild(e), e = e.onreadystatechange = null, r()
}, (a.documentElement || a.body).appendChild(e)
};
return function(e) {
n(e) && f()
}
}
return function(e) {
n(e) && setTimeout(r, 0)
}
}(),
r = function(e) {
n(function() {
throw e
})
}, i = function(e) {
return typeof e == "function"
}, s = function(e) {
return e !== null && typeof e == "object"
}, o = Object.prototype.toString,
u = Array.isArray || function(e) {
return o.call(e) === "[object Array]"
}, a = function(e) {
var t = [],
n = 0,
r = e.length;
while (n < r) t.push(n++);
return t
}, f = Object.keys || function(e) {
var t = [];
for (var n in e) e.hasOwnProperty(n) && t.push(n);
return t
}, l = function(e) {
var t = function(t) {
this.name = e, this.message = t
};
return t.prototype = new Error, t
}, c = function(e, t) {
return function(n) {
e.call(this, n, t)
}
}, h = function() {
this._promise = new d
};
h.prototype = {
promise: function() {
return this._promise
},
resolve: function(e) {
this._promise.isResolved() || this._promise._resolve(e)
},
reject: function(e) {
if (this._promise.isResolved()) return;
g.isPromise(e) ? (e = e.then(function(e) {
var t = g.defer();
return t.reject(e), t.promise()
}), this._promise._resolve(e)) : this._promise._reject(e)
},
notify: function(e) {
this._promise.isResolved() || this._promise._notify(e)
}
};
var p = {
PENDING: 0,
RESOLVED: 1,
FULFILLED: 2,
REJECTED: 3
}, d = function(e) {
this._value = t, this._status = p.PENDING, this._fulfilledCallbacks = [], this._rejectedCallbacks = [], this._progressCallbacks = [];
if (e) {
var n = this,
r = e.length;
e(function(e) {
n.isResolved() || n._resolve(e)
}, r > 1 ? function(e) {
n.isResolved() || n._reject(e)
} : t, r > 2 ? function(e) {
n.isResolved() || n._notify(e)
} : t)
}
};
d.prototype = {
valueOf: function() {
return this._value
},
isResolved: function() {
return this._status !== p.PENDING
},
isFulfilled: function() {
return this._status === p.FULFILLED
},
isRejected: function() {
return this._status === p.REJECTED
},
then: function(e, t, n, r) {
var i = new h;
return this._addCallbacks(i, e, t, n, r), i.promise()
},
"catch": function(e, n) {
return this.then(t, e, n)
},
fail: function(e, n) {
return this.then(t, e, n)
},
always: function(e, t) {
var n = this,
r = function() {
return e.call(this, n)
};
return this.then(r, r, t)
},
progress: function(e, n) {
return this.then(t, t, e, n)
},
spread: function(e, t, n) {
return this.then(function(t) {
return e.apply(this, t)
}, t, n)
},
done: function(e, t, n, i) {
this.then(e, t, n, i).fail(r)
},
delay: function(e) {
var t, n = this.then(function(n) {
var r = new h;
return t = setTimeout(function() {
r.resolve(n)
}, e), r.promise()
});
return n.always(function() {
clearTimeout(t)
}), n
},
timeout: function(e) {
var t = new h,
n = setTimeout(function() {
t.reject(new g.TimedOutError("timed out"))
}, e);
return this.then(function(e) {
t.resolve(e)
}, function(e) {
t.reject(e)
}), t.promise().always(function() {
clearTimeout(n)
}), t.promise()
},
_vow: !0,
_resolve: function(e) {
if (this._status > p.RESOLVED) return;
if (e === this) {
this._reject(TypeError("Can't resolve promise with itself"));
return
}
this._status = p.RESOLVED;
if (e && !! e._vow) {
e.isFulfilled() ? this._fulfill(e.valueOf()) : e.isRejected() ? this._reject(e.valueOf()) : e.then(this._fulfill, this._reject, this._notify, this);
return
}
if (s(e) || i(e)) {
var t;
try {
t = e.then
} catch (n) {
this._reject(n);
return
}
if (i(t)) {
var r = this,
o = !1;
try {
t.call(e, function(e) {
if (o) return;
o = !0, r._resolve(e)
}, function(e) {
if (o) return;
o = !0, r._reject(e)
}, function(e) {
r._notify(e)
})
} catch (n) {
o || this._reject(n)
}
return
}
}
this._fulfill(e)
},
_fulfill: function(e) {
if (this._status > p.RESOLVED) return;
this._status = p.FULFILLED, this._value = e, this._callCallbacks(this._fulfilledCallbacks, e), this._fulfilledCallbacks = this._rejectedCallbacks = this._progressCallbacks = t
},
_reject: function(e) {
if (this._status > p.RESOLVED) return;
this._status = p.REJECTED, this._value = e, this._callCallbacks(this._rejectedCallbacks, e), this._fulfilledCallbacks = this._rejectedCallbacks = this._progressCallbacks = t
},
_notify: function(e) {
this._callCallbacks(this._progressCallbacks, e)
},
_addCallbacks: function(e, n, r, s, o) {
r && !i(r) ? (o = r, r = t) : s && !i(s) && (o = s, s = t);
var u;
this.isRejected() || (u = {
defer: e,
fn: i(n) ? n : t,
ctx: o
}, this.isFulfilled() ? this._callCallbacks([u], this._value) : this._fulfilledCallbacks.push(u)), this.isFulfilled() || (u = {
defer: e,
fn: r,
ctx: o
}, this.isRejected() ? this._callCallbacks([u], this._value) : this._rejectedCallbacks.push(u)), this._status <= p.RESOLVED && this._progressCallbacks.push({
defer: e,
fn: s,
ctx: o
})
},
_callCallbacks: function(e, t) {
var r = e.length;
if (!r) return;
var i = this.isResolved(),
s = this.isFulfilled();
n(function() {
var n = 0,
o, u, a;
while (n < r) {
o = e[n++], u = o.defer, a = o.fn;
if (a) {
var f = o.ctx,
l;
try {
l = f ? a.call(f, t) : a(t)
} catch (c) {
u.reject(c);
continue
}
i ? u.resolve(l) : u.notify(l)
} else i ? s ? u.resolve(t) : u.reject(t) : u.notify(t)
}
})
}
};
var v = {
cast: function(e) {
return g.cast(e)
},
all: function(e) {
return g.all(e)
},
race: function(e) {
return g.anyResolved(e)
},
resolve: function(e) {
return g.resolve(e)
},
reject: function(e) {
return g.reject(e)
}
};
for (var m in v) v.hasOwnProperty(m) && (d[m] = v[m]);
var g = {
Deferred: h,
Promise: d,
defer: function() {
return new h
},
when: function(e, t, n, r, i) {
return g.cast(e).then(t, n, r, i)
},
fail: function(e, n, r) {
return g.when(e, t, n, r)
},
always: function(e, t, n) {
return g.when(e).always(t, n)
},
progress: function(e, t, n) {
return g.when(e).progress(t, n)
},
spread: function(e, t, n, r) {
return g.when(e).spread(t, n, r)
},
done: function(e, t, n, r, i) {
g.when(e).done(t, n, r, i)
},
isPromise: function(e) {
return s(e) && i(e.then)
},
cast: function(e) {
return g.isPromise(e) ? e : g.resolve(e)
},
valueOf: function(e) {
return e && i(e.valueOf) ? e.valueOf() : e
},
isFulfilled: function(e) {
return e && i(e.isFulfilled) ? e.isFulfilled() : !0
},
isRejected: function(e) {
return e && i(e.isRejected) ? e.isRejected() : !1
},
isResolved: function(e) {
return e && i(e.isResolved) ? e.isResolved() : !0
},
resolve: function(e) {
var t = g.defer();
return t.resolve(e), t.promise()
},
fulfill: function(e) {
var t = g.defer(),
n = t.promise();
return t.resolve(e), n.isFulfilled() ? n : n.then(null, function(e) {
return e
})
},
reject: function(e) {
var t = g.defer();
return t.reject(e), t.promise()
},
invoke: function(t, n) {
var r = Math.max(arguments.length - 1, 0),
i;
if (r) {
i = Array(r);
var s = 0;
while (s < r) i[s++] = arguments[s]
}
try {
return g.resolve(i ? t.apply(e, i) : t.call(e))
} catch (o) {
return g.reject(o)
}
},
all: function(e) {
var t = new h,
n = u(e),
r = n ? a(e) : f(e),
i = r.length,
s = n ? [] : {};
if (!i) return t.resolve(s), t.promise();
var o = i;
return g._forEach(e, function(e, n) {
s[r[n]] = e, --o || t.resolve(s)
}, t.reject, t.notify, t, r), t.promise()
},
allResolved: function(e) {
var t = new h,
n = u(e),
r = n ? a(e) : f(e),
i = r.length,
s = n ? [] : {};
if (!i) return t.resolve(s), t.promise();
var o = function() {
--i || t.resolve(e)
};
return g._forEach(e, o, o, t.notify, t, r), t.promise()
},
allPatiently: function(e) {
return g.allResolved(e).then(function() {
var t = u(e),
n = t ? a(e) : f(e),
r, i, s = n.length,
o = 0,
l, c;
if (!s) return t ? [] : {};
while (o < s) l = n[o++], c = e[l], g.isRejected(c) ? (r || (r = t ? [] : {}), t ? r.push(c.valueOf()) : r[l] = c.valueOf()) : r || ((i || (i = t ? [] : {}))[l] = g.valueOf(c));
if (r) throw r;
return i
})
},
any: function(e) {
var t = new h,
n = e.length;
if (!n) return t.reject(Error()), t.promise();
var r = 0,
i;
return g._forEach(e, t.resolve, function(e) {
r || (i = e), ++r === n && t.reject(i)
}, t.notify, t), t.promise()
},
anyResolved: function(e) {
var t = new h,
n = e.length;
return n ? (g._forEach(e, t.resolve, t.reject, t.notify, t), t.promise()) : (t.reject(Error()), t.promise())
},
delay: function(e, t) {
return g.resolve(e).delay(t)
},
timeout: function(e, t) {
return g.resolve(e).timeout(t)
},
_forEach: function(e, t, n, r, i, s) {
var o = s ? s.length : e.length,
u = 0;
while (u < o) g.when(e[s ? s[u] : u], c(t, u), n, r, i), ++u
},
TimedOutError: l("TimedOut")
}, y = !0;
typeof module == "object" && typeof module.exports == "object" && (module.exports = g, y = !1), typeof modules == "object" && i(modules.define) && (modules.define("vow", function(e) {
e(g)
}), y = !1), typeof define == "function" && (define(function(e, t, n) {
n.exports = g
}), y = !1), y && (e.vow = g)
})(this);
function doSomethingAsync() {
var deferred = vow.defer();
// now you can resolve, reject, notify corresponging promise within `deferred`
// e.g. `defer.resolve('ok');`
deferred.resolve();
return deferred.promise(); // and return corresponding promise to subscribe to reactions
}
Ready to run.
Test | Ops/sec | |
---|---|---|
lie |
| ready |
when |
| ready |
RSVP |
| ready |
q |
| ready |
catiline |
| ready |
bluebird |
| ready |
yui |
| ready |
JQuery |
| ready |
ES6 Promise polyfill |
| ready |
YUI + ES6 Promise polyfill |
| ready |
kew |
| ready |
MyDeferred |
| ready |
MyPromise |
| ready |
Orion |
| ready |
vow |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.