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="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js">
</script>
<script>
function Class(params) {
var extend = params.extend || function () {
},
mixin = function (dest, source) {
var name;
for (name in source) {
dest[name] = (typeof(source[name]) !== 'function' || typeof parent[name] !== "function") ? source[name] :
(function (name, fn) {
return function () {
var tmp = this._super;
this._super = parent[name];
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, source[name]);
}
return dest;
}, parent = extend.prototype;
params.__construct = params.constructor || function () {
};
delete params.constructor;
delete params.extend;
function Constructor() {
this.__construct && this.__construct.apply(this, arguments);
}
if (extend) {
Constructor.prototype = Object.create(extend.prototype);
}
mixin(Constructor.prototype, params);
Constructor.prototype.constructor = Constructor;
return Constructor;
}
/*
jQuery pub/sub plugin by Peter Higgins (dante@dojotoolkit.org)
Loosely based on Dojo publish/subscribe API, limited in scope. Rewritten blindly.
Original is (c) Dojo Foundation 2004-2010. Released under either AFL or new BSD, see:
http://dojofoundation.org/license for more information.
*/
;
(function(d) {
// the topic/subscription hash
var cache = {};
d.publish = function( /* String */ topic, /* Array? */ args) {
// summary:
// Publish some data on a named topic.
// topic: String
// The channel to publish on
// args: Array?
// The data to publish. Each array item is converted into an ordered
// arguments on the subscribed functions.
//
// example:
// Publish stuff on '/some/topic'. Anything subscribed will be called
// with a function signature like: function(a,b,c){ ... }
//
// | $.publish("/some/topic", ["a","b","c"]);
cache[topic] && d.each(cache[topic], function() {
this.apply(d, args || []);
});
};
d.subscribe = function( /* String */ topic, /* Function */ callback) {
// summary:
// Register a callback on a named topic.
// topic: String
// The channel to subscribe to
// callback: Function
// The handler event. Anytime something is $.publish'ed on a
// subscribed channel, the callback will be called with the
// published array as ordered arguments.
//
// returns: Array
// A handle which can be used to unsubscribe this particular subscription.
//
// example:
// | $.subscribe("/some/topic", function(a, b, c){ /* handle data */ });
//
if (!cache[topic]) {
cache[topic] = [];
}
cache[topic].push(callback);
return [topic, callback]; // Array
};
d.unsubscribe = function( /* Array */ handle) {
// summary:
// Disconnect a subscribed function for a topic.
// handle: Array
// The return value from a $.subscribe call.
// example:
// | var handle = $.subscribe("/something", function(){});
// | $.unsubscribe(handle);
var t = handle[0];
cache[t] && d.each(cache[t], function(idx) {
if (this == handle[1]) {
cache[t].splice(idx, 1);
}
});
};
})(jQuery);
(function($) {
var o = $({});
$.sub = function() {
o.on.apply(o, arguments);
};
$.unsub = function() {
o.off.apply(o, arguments);
};
$.pub = function() {
o.trigger.apply(o, arguments);
};
}(jQuery));
/*!
* Amplify Core 1.1.0
*
* Copyright 2011 appendTo LLC. (http://appendto.com/team)
* Dual licensed under the MIT or GPL licenses.
* http://appendto.com/open-source-licenses
*
* http://amplifyjs.com
*/
(function( global, undefined ) {
var slice = [].slice,
subscriptions = {};
var amplify = global.amplify = {
publish: function( topic ) {
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 ( 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 ( !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 ) );
//Copyright (c) 2010 Nicholas C. Zakas. All rights reserved.
//MIT License
var CustomEvent = new Class({
constructor: function() {
this._listeners = {};
},
addListener: function(type, listener) {
if (typeof this._listeners[type] === "undefined") {
this._listeners[type] = [];
}
this._listeners[type].push(listener);
},
fire: function(event) {
if (typeof event === "string") {
event = {type: event};
}
if (!event.target) {
event.target = this;
}
if (!event.type) { //falsy
throw new Error("Event object missing 'type' property.");
}
if (this._listeners[event.type] instanceof Array) {
var listeners = this._listeners[event.type];
for (var i = 0, len = listeners.length; i < len; i++) {
listeners[i].call(this, event);
}
}
},
removeListener: function(type, listener) {
if (this._listeners[type] instanceof Array) {
var listeners = this._listeners[type];
for (var i = 0, len = listeners.length; i < len; i++) {
if (listeners[i] === listener) {
listeners.splice(i, 1);
break;
}
}
}
},
hasListeners: function(type) {
if (this._listeners[type] instanceof Array) {
return (this._listeners[type].length > 0);
} else {
return false;
}
},
getListeners:function(type) {
if (this._listeners[type] instanceof Array) {
return this._listeners[type];
}
}
});
var pubSub = (function() {
var topics = {},
subUid = -1;
return {
publish: function(topic, args) {
if (!topics[topic]) {
return false;
}
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;
while (len--) {
subscribers[len].func(topic, args);
}
return this;
},
subscribe: function(topic, func) {
if (!topics[topic]) {
topics[topic] = [];
}
var token = (++subUid).toString();
topics[topic].push({
token: token,
func: func
});
return token;
},
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 this;
}
};
})();
</script>
for (var i = 0; i < 1000; i++) {
$.subscribe('topic_' + i, function() {});
}
for (var i = 0; i < 1000; i++) {
$.sub('topic_' + i, function() {});
}
for (var i = 0; i < 1000; i++) {
amplify.subscribe('topic_' + i, function() {});
}
var target = new EventTarget();
for (var i = 0; i < 1000; i++) {
target.addListener("topic_", function() {});
}
for (var i = 0; i < 1000; i++) {
pubSub.subscribe('topic_' + i, function() {});
}
/**
* Observable pattern.
* @class PlusNode.helpers.Observable
* @constructor
* @requires PlusNode.helpers.Event
*/
var Observable = (function(){
var isType = function (compare) {
if (typeof compare === 'string' && /^\w+$/.test(compare)) {
compare = '[object ' + compare + ']';
} else {
compare = Object.prototype.toString.call(compare);
}
return isType[compare] || (isType[compare] = function (o) {
return Object.prototype.toString.call(o) === compare;
});
};
return Class({
constructor:function () {
this.events = {};
},
/**
* call example: <pre class='brush:js'>
* fireEvent('eventName');
* fireEvent('eventName',[arguments]);
* fireEvent('eventName','listenerId',[arguments]);
* </pre>
* @method fireEvent
* @param {String} eventName
* @param {String} listenerId
* @param {Object|String} args arguments passed to listener
*/
fireEvent:function (eventName, listenerId, args) {
if (!this.events[eventName]) {
return console.warn("no such event ID: " + eventName);
}
//no specific listenerId,fire all the listeners
if (typeof(listenerId) != "string") {
if (typeof(args) == "undefined") {
//if there are only 2 arguments, the second one is the argument to pass when event got fired
args = listenerId;
}
return this.events[eventName].fireListener(null,args);
}
//has specific listenerId, fire this listener
if (!this.events[eventName].findListener(listenerId)) {
return console.warn("no such listener ID: " + listenerId + " for event " + eventName);
}
return this.events[eventName].fireListener(listenerId,args);
},
emit:function () {
return this.fireEvent.apply(this, arguments)
},
/**
* @example
* listeners example:
* <pre class='brush:js'>
* listeners : [{
* id:'listener1',
* content:function(args){//do sth. }
* }]
* </pre>
* @method addEvent
* @param {String} eventName
* @param {Array} listeners
* @return {Array} list of added listeners
*/
addEvent:function (eventName, listeners) {
var l = [];
eventName = eventName.trim();
if (!this.events[eventName]) {
this.events[eventName] = new Event(eventName);
}
if (isType('Function')(listeners)) {
listeners = this.listenerToArray(listeners);
}
if (isType('Object')(listeners)) {
listeners = this.listenersToArray(listeners);
}
if (Array.isArray(listeners)) {
listeners.forEach(function (listener) {
l.push(this.events[eventName].addListener(listener));
}, this);
}
if (l.length == 1) {
return l.shift();
}
l.remove = function () {
this.forEach(function (el) {
if (!el || !el.remove) {
return;
}
el.remove();
});
};
return l;
},
listenersToArray:function (listeners) {
var li = [];
Object.keys(listeners).forEach(function (name) {
li.push({
id:name,
content:listeners[name]
});
});
return li
},
listenerToArray:function (listener) {
return [
{
id:"#Listener:" + (new Date()).getTime() + Math.floor(Math.random() * 100),
content:listener
}
];
},
once:function (event, listeners) {
if (isType('Function')(listeners)) {
listeners = this.listenerToArray(listeners);
}
listeners = listeners.map(function (item) {
item.single = true;
return item;
});
return this.addEvent(event, listeners);
},
on:function () {
return this.addEvent.apply(this, arguments);
},
/**
* detect if has an event of a listener
* @method hasEvent
* @param {String} eventName
* @param {String} listenerId (optional) if listenerId is defined, return this listener or false
* @return {false|Object}
*/
hasEvent:function (eventName, listenerId) {
var hasEvent = this.events[eventName] || false;
if (hasEvent && listenerId) {
return hasEvent.findListener(listenerId) || false;
}
return hasEvent;
},
/**
* @method removeEvent
* @param {String} eventName
* @param {String} listenerId
*/
removeEvent:function (eventName, listenerId) {
if (!this.events[eventName]) {
console.warn("no such event ID: " + eventName);
return;
}
if (!listenerId) {
this.events[eventName].purgeListeners();
delete this.events[eventName];
return;
}
return this.events[eventName].removeListener(listenerId);
},
off:function () {
return this.removeEvent.apply(this, arguments)
}
});
})();
Ready to run.
Test | Ops/sec | |
---|---|---|
Peter Higgins |
| ready |
Tiny Pubsub |
| ready |
Amplify |
| ready |
Nicholas C. Zakas JS Custom Events |
| ready |
pubsub simple |
| ready |
Observable |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.