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
An attempt at showing that PubSubJS is faster than using jQuery custom evens for publish/subscribe style messaging.
It's certainly not as rich in features, and I am happy with that.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
/*! Tiny Pub/Sub - v0.7.0 - 2013-01-29
* https://github.com/cowboy/jquery-tiny-pubsub
* Copyright (c) 2013 "Cowboy" Ben Alman; Licensed MIT */
(function($) {
var o = $({});
$.subscribe = function() {
o.on.apply(o, arguments);
};
$.unsubscribe = function() {
o.off.apply(o, arguments);
};
$.publish = function() {
o.trigger.apply(o, arguments);
};
}(jQuery));
/*
Copyright (c) 2010,2011,2012 Morgan Roderick http://roderick.dk
License: MIT - http://mrgnrdrck.mit-license.org
https://github.com/mroderick/PubSubJS
*/
/*jslint white:true, plusplus:true, stupid:true*/
/*global
setTimeout,
module,
exports,
define,
require,
window
*/
(function(root, factory){
'use strict';
// CommonJS
if (typeof exports === 'object'){
module.exports = factory();
// AMD
} else if (typeof define === 'function' && define.amd){
define(factory);
// Browser
} else {
root.PubSub = factory();
}
}( ( typeof window === 'object' && window ) || this, function(){
'use strict';
var PubSub = {
name: 'PubSubJS',
version: '1.3.5'
},
messages = {},
lastUid = -1;
/**
* Returns a function that throws the passed exception, for use as argument for setTimeout
* @param { Object } ex An Error object
*/
function throwException( ex ){
return function reThrowException(){
throw ex;
};
}
function callSubscriberWithDelayedExceptions( subscriber, message, data ){
try {
subscriber( message, data );
} catch( ex ){
setTimeout( throwException( ex ), 0);
}
}
function callSubscriberWithImmediateExceptions( subscriber, message, data ){
subscriber( message, data );
}
function deliverMessage( originalMessage, matchedMessage, data, immediateExceptions ){
var subscribers = messages[matchedMessage],
callSubscriber = immediateExceptions ? callSubscriberWithImmediateExceptions : callSubscriberWithDelayedExceptions,
i, j;
if ( !messages.hasOwnProperty( matchedMessage ) ) {
return;
}
for ( i = 0, j = subscribers.length; i < j; i++ ){
callSubscriber( subscribers[i].func, originalMessage, data );
}
}
function createDeliveryFunction( message, data, immediateExceptions ){
return function deliverNamespaced(){
var topic = String( message ),
position = topic.lastIndexOf( '.' );
// deliver the message as it is now
deliverMessage(message, message, data, immediateExceptions);
// trim the hierarchy and deliver message to each level
while( position !== -1 ){
topic = topic.substr( 0, position );
position = topic.lastIndexOf('.');
deliverMessage( message, topic, data );
}
};
}
function messageHasSubscribers( message ){
var topic = String( message ),
found = messages.hasOwnProperty( topic ),
position = topic.lastIndexOf( '.' );
while ( !found && position !== -1 ){
topic = topic.substr( 0, position );
position = topic.lastIndexOf('.');
found = messages.hasOwnProperty( topic );
}
return found;
}
function publish( message, data, sync, immediateExceptions ){
var deliver = createDeliveryFunction( message, data, immediateExceptions ),
hasSubscribers = messageHasSubscribers( message );
if ( !hasSubscribers ){
return false;
}
if ( sync === true ){
deliver();
} else {
setTimeout( deliver, 0 );
}
return true;
}
/**
* PubSub.publish( message[, data] ) -> Boolean
* - message (String): The message to publish
* - data: The data to pass to subscribers
* Publishes the the message, passing the data to it's subscribers
**/
PubSub.publish = function( message, data ){
return publish( message, data, false, PubSub.immediateExceptions );
};
/**
* PubSub.publishSync( message[, data] ) -> Boolean
* - message (String): The message to publish
* - data: The data to pass to subscribers
* Publishes the the message synchronously, passing the data to it's subscribers
**/
PubSub.publishSync = function( message, data ){
return publish( message, data, true, PubSub.immediateExceptions );
};
/**
* PubSub.subscribe( message, func ) -> String
* - message (String): The message to subscribe to
* - func (Function): The function to call when a new message is published
* Subscribes the passed function to the passed message. Every returned token is unique and should be stored if
* you need to unsubscribe
**/
PubSub.subscribe = function( message, func ){
// message is not registered yet
if ( !messages.hasOwnProperty( message ) ){
messages[message] = [];
}
// forcing token as String, to allow for future expansions without breaking usage
// and allow for easy use as key names for the 'messages' object
var token = String(++lastUid);
messages[message].push( { token : token, func : func } );
// return token for unsubscribing
return token;
};
/**
* PubSub.unsubscribe( tokenOrFunction ) -> String | Boolean
* - tokenOrFunction (String|Function): The token of the function to unsubscribe or func passed in on subscribe
* Unsubscribes a specific subscriber from a specific message using the unique token
* or if using Function as argument, it will remove all subscriptions with that function
**/
PubSub.unsubscribe = function( tokenOrFunction ){
var isToken = typeof tokenOrFunction === 'string',
key = isToken ? 'token' : 'func',
succesfulReturnValue = isToken ? tokenOrFunction : true,
result = false,
m, i;
for ( m in messages ){
if ( messages.hasOwnProperty( m ) ){
for ( i = messages[m].length-1 ; i >= 0; i-- ){
if ( messages[m][i][key] === tokenOrFunction ){
messages[m].splice( i, 1 );
result = succesfulReturnValue;
// tokens are unique, so we can just return here
if ( isToken ){
return result;
}
}
}
}
}
return result;
};
return PubSub;
}));
/*! pubbie 2013-03-28 */
(function(){(function(n){var t,e,i,r;return t={},r=-1,i={},e={subscribe:function(n,e){var u;return t.hasOwnProperty(n)||(t[n]=[]),u=r+=1,t[n].push({id:u,fn:e}),i[u]={namespace:n,index:t[n].length-1},u},publish:function(n,e){var i,r,u,s,c;for(r=t[n]||[],u=function(n){return n.fn.apply(this,e||[])},s=0,c=r.length;c>s;s++)i=r[s],u(i);return this},unsubscribe:function(n){var e,r;return e="string"==typeof n,e?t[n]=[]:(r=i[n],t[r.namespace].splice(r.index,1)),this},reset:function(){return t={},r=-1,this}},n.pubbie=n.pubbie||e})(window,window.document)}).call(this);
(function( global, undefined ) {
var slice = [].slice,
subscriptions = {};
var amplify = global.amplify = {
publish: function( topic ) {
if ( typeof topic !== "string" ) {
throw new Error( "You must provide a valid topic to publish." );
}
var args = slice.call( arguments, 1 ),
topicSubscriptions,
subscription,
length,
i = 0,
ret;
if ( !subscriptions[ topic ] ) {
return true;
}
topicSubscriptions = subscriptions[ topic ].slice();
for ( length = topicSubscriptions.length; i < length; i++ ) {
subscription = topicSubscriptions[ i ];
ret = subscription.callback.apply( subscription.context, args );
if ( ret === false ) {
break;
}
}
return ret !== false;
},
subscribe: function( topic, context, callback, priority ) {
if ( typeof topic !== "string" ) {
throw new Error( "You must provide a valid topic to create a subscription." );
}
if ( arguments.length === 3 && typeof callback === "number" ) {
priority = callback;
callback = context;
context = null;
}
if ( arguments.length === 2 ) {
callback = context;
context = null;
}
priority = priority || 10;
var topicIndex = 0,
topics = topic.split( /\s/ ),
topicLength = topics.length,
added;
for ( ; topicIndex < topicLength; topicIndex++ ) {
topic = topics[ topicIndex ];
added = false;
if ( !subscriptions[ topic ] ) {
subscriptions[ topic ] = [];
}
var i = subscriptions[ topic ].length - 1,
subscriptionInfo = {
callback: callback,
context: context,
priority: priority
};
for ( ; i >= 0; i-- ) {
if ( subscriptions[ topic ][ i ].priority <= priority ) {
subscriptions[ topic ].splice( i + 1, 0, subscriptionInfo );
added = true;
break;
}
}
if ( !added ) {
subscriptions[ topic ].unshift( subscriptionInfo );
}
}
return callback;
},
unsubscribe: function( topic, callback ) {
if ( typeof topic !== "string" ) {
throw new Error( "You must provide a valid topic to remove a subscription." );
}
if ( !subscriptions[ topic ] ) {
return;
}
var length = subscriptions[ topic ].length,
i = 0;
for ( ; i < length; i++ ) {
if ( subscriptions[ topic ][ i ].callback === callback ) {
subscriptions[ topic ].splice( i, 1 );
break;
}
}
}
};
}( this ) );
/*!
* Pub/Sub implementation
* http://addyosmani.com/
* Licensed under the GPL
* http://jsfiddle.net/LxPrq/
*/
;(function ( window, doc, undef ) {
var topics = {},
subUid = -1,
pubsubz ={};
pubsubz.publish = function ( topic, args ) {
if (!topics[topic]) {
return false;
}
setTimeout(function () {
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(topic, args);
}
}, 0);
return true;
};
pubsubz.subscribe = function ( topic, func ) {
if (!topics[topic]) {
topics[topic] = [];
}
var token = (++subUid).toString();
topics[topic].push({
token: token,
func: func
});
return token;
};
pubsubz.unsubscribe = function ( token ) {
for (var m in topics) {
if (topics[m]) {
for (var i = 0, j = topics[m].length; i < j; i++) {
if (topics[m][i].token === token) {
topics[m].splice(i, 1);
return token;
}
}
}
}
return false;
};
getPubSubz = function(){
return pubsubz;
};
window.pubsubz = getPubSubz();
}( this, this.document ));
</script>
<script>
var callback1 = function(args) {
return false;
};
var payload = {
somekey: 'some value'
};
for(var i = 0, l = 100; i < l; i++) {
$.subscribe('event' + i, callback1);
PubSub.subscribe('event' + i, callback1);
pubbie.subscribe('event' + i, callback1);
amplify.subscribe('event' + i, callback1);
pubsubz.subscribe('event' + i, callback1);
}
</script>
Ready to run.
Test | Ops/sec | |
---|---|---|
jQuery DOM - trigger |
| ready |
jQuery Object - trigger |
| ready |
PubSub - publish - asyncronous |
| ready |
PubSub - publish - syncronous |
| ready |
jQuery document - trigger |
| ready |
pubbie |
| ready |
amplify |
| ready |
pubsubz |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.