promise comparisons

JavaScript performance comparison

Revision 55 of this test case created by Brian Cavalier

Preparation code

<script src="https://rawgithub.com/petkaantonov/bluebird/master/js/bluebird.js">
</script>
<script>
  window.BluebirdPromise = window.Promise.noConflict();
console.log(BluebirdPromise);
</script>
<script src="https://rawgithub.com/calvinmetcalf/lie/mutation/dist/lie.noConflict.js"></script><script src="http://rsvpjs-builds.s3.amazonaws.com/rsvp-latest.js"></script>
<script src="https://rawgithub.com/calvinmetcalf/catiline/mutation/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>
(function(e){if("function"==typeof bootstrap)bootstrap("promise",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makePromise=e}else"undefined"!=typeof window?window.Promise=e():global.Promise=e()})(function(){var define,ses,bootstrap,module,exports;
return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var nextTick, handlerQueue, bind, uncurryThis, call, MutationObserver, undef;

bind = Function.prototype.bind;
uncurryThis = bind.bind(bind.call);
call = uncurryThis(bind.call);

module.exports = Promise;

Promise.resolve = resolve;
Promise.cast    = cast;
Promise.reject  = reject;
Promise.all     = all;
Promise.race    = race;

// Return a pending promise whose fate is determined by resolver
function Promise(resolver) {
	var value, handlers = [];

	this.when = function(onFulfilled, onRejected, resolve) {
		handlers ? handlers.push(deliver) : enqueue(deliver);

		function deliver() {
			value.when(onFulfilled, onRejected, resolve);
		}
	};

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

	// Reject with reason verbatim
	function promiseReject(reason) {
		promiseResolve(new Rejected(reason));
	}

	// Resolve with a value, promise, or thenable
	function promiseResolve(x) {
		if(!handlers) {
			return;
		}

		var queue = handlers;
		handlers = undef;

		enqueue(function () {
			value = coerce(x);
			for(var i=0; i<queue.length; ++i) {
				queue[i]();
			}
//			queue.forEach(function(handler) {
//				handler();
//			});
		});
	}
}

Promise.prototype.then = function(onFulfilled, onRejected) {
	var self = this;
	return new Promise(function(resolve) {
		self.when(onFulfilled, onRejected, resolve);
	});
};

Promise.prototype.done = function(task) {
	this.when(task, function(e) {
		enqueue(function() { throw e; });
	}, noop);
}

Promise.prototype['catch'] = function(onRejected) {
	return this.then(null, onRejected);
};

// Coerce x to a promise
function coerce(x) {
	if(x instanceof Promise) {
		return x;
	}

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

	return new Promise(function(resolve, reject) {
		try {
			var untrustedThen = x.then;

			if(typeof untrustedThen === 'function') {
				call(untrustedThen, x, resolve, reject);
			} else {
				resolve(new Fulfilled(x));
			}
		} catch(e) {
			reject(e);
		}
	});
}

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

Fulfilled.prototype = Object.create(Promise.prototype);
Fulfilled.prototype.when = function(onFulfilled, _, resolve) {
	try {
		resolve(typeof onFulfilled == 'function'
			? onFulfilled(this.value) : this);
	} catch (e) {
		resolve(new Rejected(e));
	}
};

function Rejected(reason) {
	this.value = reason;
}

Rejected.prototype = Object.create(Promise.prototype);
Rejected.prototype.when = function(_, onRejected, resolve) {
	try {
		resolve(typeof onRejected == 'function'
			? onRejected(this.value) : this);
	} catch (e) {
		resolve(new Rejected(e));
	}
};

function cast(x) {
	return x instanceof Promise ? x : resolve(x);
}

function resolve(x) {
	return new Promise(function(resolve) {
		resolve(x);
	});
}

function reject(x) {
	return new Promise(function(_, reject) {
		reject(x);
	});
}

// Return a promise that will fulfill after all promises in array
// have fulfilled, or will reject after one promise in array rejects
function all(array) {
	return new Promise(resolveAll);

	function resolveAll(resolve, reject) {
		var results, toResolve = array.length;

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

		results = [];
		array.forEach(function(item, i) {
			cast(item).then(function(value) {
				results[i] = value;

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

function race(array) {
	return new Promise(resolveRace);

	function resolveRace(resolve, reject) {
		array.forEach(function(item) {
			cast(item).then(resolve, reject);
		});
	}
}

function noop() {}

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

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

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

// Sniff "best" async scheduling option
/*global process,window,document*/
if (typeof process === 'object' && process.nextTick) {
	nextTick = process.nextTick;
} else if(typeof window !== 'undefined' && (MutationObserver = window.MutationObserver || window.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 {
	nextTick = function(t) { setTimeout(t, 0); };
}
},{}]},{},[1])
(1)
});
;</script>
    

Preparation code output

Test runner

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

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
lie
// async test
var d = lie();
var code = 'lie' + Math.random();
function eventFunc(e) {
  if (e === code) {
worker.off('pong');
    d.resolve();
}
}
worker.on('pong',eventFunc);
d.promise.then(function() {
  deferred.resolve()
})
worker.fire('ping',code);
pending…
when
// async test
var code = 'when' + Math.random();
var promise = when.promise(function(resolve) {
  function eventFunc(e) {
    if (e === code) {
      worker.off('pong');
      resolve();
    }
  }
  worker.on('pong',eventFunc);
});

promise.then(function() {
  deferred.resolve()
})
worker.fire('ping',code);
pending…
RSVP
// async test
var d = RSVP.defer();
var code = 'rsvp' + Math.random();
function eventFunc(e) {
  if (e === code) {
worker.off('pong');
    d.resolve();
}
}
worker.on('pong',eventFunc);
d.promise.then(function() {
  deferred.resolve()
})
worker.fire('ping',code);
pending…
q
// async test
var d = Q.defer()
var code = 'q' + Math.random();
function eventFunc(e) {
  if (e === code) {
worker.off('pong');
    d.resolve();
}
}
worker.on('pong',eventFunc);
d.promise.then(function() {
  deferred.resolve()
})
worker.fire('ping',code);
pending…
catiline
// async test
var d = cw.deferred()
var code = 'cw' + Math.random();
function eventFunc(e) {
  if (e === code) {
worker.off('pong');
    d.resolve();
}
}
worker.on('pong',eventFunc);
d.promise.then(function() {
  deferred.resolve()
})
worker.fire('ping',code);
pending…
truth
// async test
var code = 'truth' + Math.random();
var promise = new Promise(function(resolve) {
  function eventFunc(e) {
    if (e === code) {
      worker.off('pong');
      resolve();
    }
  }
  worker.on('pong',eventFunc);
});

promise.then(function() {
  deferred.resolve()
})
worker.fire('ping',code);
pending…
bluebird
// async test
console.log(BluebirdPromise);
var code = 'bluebird' + Math.random();
var promise = new BluebirdPromise(function(resolve) {
  function eventFunc(e) {
    if (e === code) {
      worker.off('pong');
      resolve();
    }
  }
  worker.on('pong',eventFunc);
});

promise.then(function() {
  deferred.resolve()
})
worker.fire('ping',code);
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.

0 Comments