promise comparisons

JavaScript performance comparison

Revision 54 of this test case created by Brian Cavalier

Info

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.

Preparation code

<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="//rawgithub.com/calvinmetcalf/catiline/mutation/dist/catiline.js"></script>

<script src="//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/truth/when.js">
</script><script>
var worker = cw({
    init:function(self){
        self.on('ping',function(d){
            self.fire('pong',d);
        });
}
    });
</script>
<script>
(function(){function require(path,parent,orig){var resolved=require.resolve(path);if(null==resolved){orig=orig||path;parent=parent||"root";var err=new Error('Failed to require "'+orig+'" from "'+parent+'"');err.path=orig;err.parent=parent;err.require=true;throw err}var module=require.modules[resolved];if(!module._resolving&&!module.exports){var mod={};mod.exports={};mod.client=mod.component=true;module._resolving=true;module.call(this,mod.exports,require.relative(resolved),mod);delete module._resolving;module.exports=mod.exports}return module.exports}require.modules={};require.aliases={};require.resolve=function(path){if(path.charAt(0)==="/")path=path.slice(1);var paths=[path,path+".js",path+".json",path+"/index.js",path+"/index.json"];for(var i=0;i<paths.length;i++){var path=paths[i];if(require.modules.hasOwnProperty(path))return path;if(require.aliases.hasOwnProperty(path))return require.aliases[path]}};require.normalize=function(curr,path){var segs=[];if("."!=path.charAt(0))return path;curr=curr.split("/");path=path.split("/");for(var i=0;i<path.length;++i){if(".."==path[i]){curr.pop()}else if("."!=path[i]&&""!=path[i]){segs.push(path[i])}}return curr.concat(segs).join("/")};require.register=function(path,definition){require.modules[path]=definition};require.alias=function(from,to){if(!require.modules.hasOwnProperty(from)){throw new Error('Failed to alias "'+from+'", it does not exist')}require.aliases[to]=from};require.relative=function(parent){var p=require.normalize(parent,"..");function lastIndexOf(arr,obj){var i=arr.length;while(i--){if(arr[i]===obj)return i}return-1}function localRequire(path){var resolved=localRequire.resolve(path);return require(resolved,parent,path)}localRequire.resolve=function(path){var c=path.charAt(0);if("/"==c)return path.slice(1);if("."==c)return require.normalize(p,path);var segs=parent.split("/");var i=lastIndexOf(segs,"deps")+1;if(!i)i=0;path=segs.slice(0,i+1).join("/")+"/deps/"+path;return path};localRequire.exists=function(path){return require.modules.hasOwnProperty(localRequire.resolve(path))};return localRequire};require.register("calvinmetcalf-setImmediate/lib/index.js",function(exports,require,module){"use strict";var types=[require("./nextTick"),require("./mutation"),require("./postMessage"),require("./messageChannel"),require("./stateChange"),require("./timeout")];var handlerQueue=[];function drainQueue(){var i=0,task,innerQueue=handlerQueue;handlerQueue=[];while(task=innerQueue[i++]){task()}}var nextTick;types.some(function(obj){var t=obj.test();if(t){nextTick=obj.install(drainQueue)}return t});var retFunc=function(task){var len,args;if(arguments.length>1&&typeof task==="function"){args=Array.prototype.slice.call(arguments,1);args.unshift(undefined);task=task.bind.apply(task,args)}if((len=handlerQueue.push(task))===1){nextTick(drainQueue)}return len};retFunc.clear=function(n){if(n<=handlerQueue.length){handlerQueue[n-1]=function(){}}return this};module.exports=retFunc});require.register("calvinmetcalf-setImmediate/lib/nextTick.js",function(exports,require,module){"use strict";exports.test=function(){return typeof process==="object"&&Object.prototype.toString.call(process)==="[object process]"};exports.install=function(){return process.nextTick}});require.register("calvinmetcalf-setImmediate/lib/postMessage.js",function(exports,require,module){"use strict";var globe=require("./global");exports.test=function(){if(!globe.postMessage||globe.importScripts){return false}var postMessageIsAsynchronous=true;var oldOnMessage=globe.onmessage;globe.onmessage=function(){postMessageIsAsynchronous=false};globe.postMessage("","*");globe.onmessage=oldOnMessage;return postMessageIsAsynchronous};exports.install=function(func){var codeWord="com.calvinmetcalf.setImmediate"+Math.random();function globalMessage(event){if(event.source===globe&&event.data===codeWord){func()}}if(globe.addEventListener){globe.addEventListener("message",globalMessage,false)}else{globe.attachEvent("onmessage",globalMessage)}return function(){globe.postMessage(codeWord,"*")}}});require.register("calvinmetcalf-setImmediate/lib/messageChannel.js",function(exports,require,module){"use strict";var globe=require("./global");exports.test=function(){return!!globe.MessageChannel};exports.install=function(func){var channel=new globe.MessageChannel;channel.port1.onmessage=func;return function(){channel.port2.postMessage(0)}}});require.register("calvinmetcalf-setImmediate/lib/stateChange.js",function(exports,require,module){"use strict";var globe=require("./global");exports.test=function(){return"document"in globe&&"onreadystatechange"in globe.document.createElement("script")};exports.install=function(handle){return function(){var scriptEl=globe.document.createElement("script");scriptEl.onreadystatechange=function(){handle();scriptEl.onreadystatechange=null;scriptEl.parentNode.removeChild(scriptEl);scriptEl=null};globe.document.documentElement.appendChild(scriptEl);return handle}}});require.register("calvinmetcalf-setImmediate/lib/timeout.js",function(exports,require,module){"use strict";exports.test=function(){return true};exports.install=function(t){return function(){setTimeout(t,0)}}});require.register("calvinmetcalf-setImmediate/lib/global.js",function(exports,require,module){module.exports=typeof global==="object"&&global?global:this});require.register("calvinmetcalf-setImmediate/lib/mutation.js",function(exports,require,module){"use strict";var globe=require("./global");var MutationObserver=globe.MutationObserver||globe.WebKitMutationObserver;exports.test=function(){return MutationObserver};exports.install=function(handle){var observer=new MutationObserver(handle);var element=globe.document.createElement("div");observer.observe(element,{attributes:true});globe.addEventListener("unload",function(){observer.disconnect();observer=null},false);return function(){element.setAttribute("drainQueue","drainQueue")}}});require.register("truth/Promise.js",function(exports,require,module){var enqueue=require("immediate");var bind=Function.prototype.bind;var uncurryThis=bind.bind(bind.call);var call=uncurryThis(bind.call);module.exports=Promise;Promise.resolve=resolve;Promise.cast=cast;Promise.reject=reject;Promise.all=all;function Promise(resolver){var value,handlers=[];this.when=function(onFulfilled,onRejected,resolve){handlers?handlers.push(deliver):enqueue(function(){deliver(value)});function deliver(p){p.when(onFulfilled,onRejected,resolve)}};try{resolver(promiseResolve,promiseReject)}catch(e){promiseReject(e)}function promiseReject(reason){promiseResolve(new RejectedPromise(reason))}function promiseResolve(x){if(!handlers){return}var queue=handlers;handlers=void 0;enqueue(function(){value=coerce(x);queue.forEach(function(handler){handler(value)})})}}Promise.prototype.then=function(onFulfilled,onRejected){var when=this.when;return new Promise(function(resolve){when(onFulfilled,onRejected,resolve)})};Promise.prototype.done=function(task){this.when(task,function(e){enqueue(function(){throw e})},function(){})};Promise.prototype["catch"]=function(onRejected){return this.then(null,onRejected)};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)})}function all(array){return cast(array).then(function(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(mapped){results[i]=mapped;if(!--toResolve){resolve(results)}},reject)})}})}function coerce(x){if(x instanceof Promise){return x}if(!(x===Object(x)&&"then"in x)){return new FulfilledPromise(x)}return new Promise(function(resolve,reject){enqueue(function(){try{var untrustedThen=x.then;if(typeof untrustedThen==="function"){call(untrustedThen,x,resolve,reject)}else{resolve(new FulfilledPromise(x))}}catch(e){reject(e)}})})}function FulfilledPromise(value){this.value=value}FulfilledPromise.prototype=Object.create(Promise.prototype);FulfilledPromise.prototype.when=function(onFulfilled,_,resolve){try{resolve(typeof onFulfilled=="function"?onFulfilled(this.value):this.value)}catch(e){resolve(new RejectedPromise(e))}};function RejectedPromise(reason){this.value=reason}RejectedPromise.prototype=Object.create(Promise.prototype);RejectedPromise.prototype.when=function(_,onRejected,resolve){try{resolve(typeof onRejected=="function"?onRejected(this.value):this)}catch(e){resolve(new RejectedPromise(e))}}});require.alias("calvinmetcalf-setImmediate/lib/index.js","truth/deps/immediate/lib/index.js");require.alias("calvinmetcalf-setImmediate/lib/nextTick.js","truth/deps/immediate/lib/nextTick.js");require.alias("calvinmetcalf-setImmediate/lib/postMessage.js","truth/deps/immediate/lib/postMessage.js");require.alias("calvinmetcalf-setImmediate/lib/messageChannel.js","truth/deps/immediate/lib/messageChannel.js");require.alias("calvinmetcalf-setImmediate/lib/stateChange.js","truth/deps/immediate/lib/stateChange.js");require.alias("calvinmetcalf-setImmediate/lib/timeout.js","truth/deps/immediate/lib/timeout.js");require.alias("calvinmetcalf-setImmediate/lib/global.js","truth/deps/immediate/lib/global.js");require.alias("calvinmetcalf-setImmediate/lib/mutation.js","truth/deps/immediate/lib/mutation.js");require.alias("calvinmetcalf-setImmediate/lib/index.js","truth/deps/immediate/index.js");require.alias("calvinmetcalf-setImmediate/lib/index.js","immediate/index.js");require.alias("calvinmetcalf-setImmediate/lib/index.js","calvinmetcalf-setImmediate/index.js");require.alias("truth/Promise.js","truth/index.js");if(typeof exports=="object"){module.exports=require("truth")}else if(typeof define=="function"&&define.amd){define(function(){return require("truth")})}else{this["Promise"]=require("truth")}})();
</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
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
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…

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