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
More info: publish/subscribe on Wikipedia.
Compared:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript">
</script>
<script src="https://raw.github.com/mroderick/PubSubJS/master/src/pubsub.js" type="text/javascript">
</script>
<script src="https://raw.github.com/kuwabarahiroshi/bloody-jquery-plugins/master/pubsub.js" type="text/javascript">
</script>
<script src="https://raw.github.com/phiggins42/bloody-jquery-plugins/55e41df9bf08f42378bb08b93efcb28555b61aeb/pubsub.js" type="text/javascript">
</script>
<script src="https://raw.github.com/gist/1695338/736bcf94f9226d975fce3ad4f2bc08ccbf176bad/pubsub.js" type="text/javascript">
</script>
<script src="https://raw.github.com/appendto/amplify/master/core/amplify.core.js" type="text/javascript">
</script>
<script src="https://raw.github.com/maccman/spine/master/lib/spine.js" type="text/javascript">
</script>
<script src="https://raw.github.com/richardscarrott/ply/master/src/core.js" type="text/javascript">
</script>
<script src="https://raw.github.com/jrburke/requirejs/master/require.js" type="text/javascript">
</script>
<script type="text/javascript">
window.callback = function () {};
window.payload = {
somekey: 'some value'
};
var Observer = jQuery({});
jQuery(function() {
require(["https://raw.github.com/jkroso/Observer/master/lib/Observer.js"], function(Hyraki){
window.hyraki = new Hyraki()
for (var i = 0; i < 10; i++) {
Observer.on('my-event-' + i, callback);
PubSub.subscribe('my-event-' + i, callback);
jQuery.subscribe('my-event-' + i, callback);
Events.subscribe('my-event-' + i, callback);
App.subscribe('my-event-' + i, callback);
amplify.subscribe('my-event-' + i, callback);
Spine.bind('my-event-' + i, callback);
Ply.core.listen('my-event-' + i, callback);
hyraki.on('my-event-' + i, callback);
}
})
});
</script>
<script>
(function () { window.archi = window.archi || {}; }());
/*
config = {
templateDir: '/templates/', // null/undefined if you don't want to dynamically include the templates
// if a templateDir is NOT specified (you don't want to use dynamic templates), and your modules will be using
// templates, you need to define them here so the Core can pass them to the modules. If both the templateDir and
// the templates properties are defined in the config option, the Core will treat the templates object that's passed
// here as the one with priority.
templates: {
'name': 'templateName',
'template': 'template'
},
extDir: '/js/', // where is the extensions are located
moduleDir: '/js/modules/', // null/undefined if you don't want to dynamically include the modules
apiBase: '', // null/undefined if none
apiKey: '', // null/undefined if none
sessionId: '', // null/undefined if none
extensions: []
};
*/
(function (win, doc, ns, undef) {
"use strict";
// cover needed methods (from MDN)
if (!Array.prototype.some) {
Array.prototype.some = function(fun /*, thisp */) {
if (this === null)
throw new TypeError();
var t = new Object(this);
var len = t.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++) {
if (i in t && fun.call(thisp, t[i], i, t))
return true;
}
return false;
};
}
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun /*, thisp */) {
if (this === null)
throw new TypeError();
var t = new Object(this);
var len = t.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var res = [];
var thisp = arguments[1];
for (var i = 0; i < len; i++) {
if (i in t) {
var val = t[i]; // in case fun mutates this
if (fun.call(thisp, val, i, t))
res.push(val);
}
}
return res;
};
}
var Core = (function (conf) {
var Public = {extensions: []},
Private = {
templateDir: conf && Private.addSlash(conf.templateDir) || null,
modulesDir: conf && Private.addSlash(conf.moduleDir) || null,
extDir: conf && Private.addSlash(conf.extDir) || null,
apiBase: conf && conf.apiBase || null,
apiKey: conf && conf.apiKey || null,
sid: conf && conf.sessionId || null,
debug: true,
modules: {},
expects: {}
};
Public.extend = function (name, callback) {
var params = [win, doc, Public, Private, ns.Sanbox], method, methods = [], extension;
extension = callback.call(Public, Public);
for (method in extension) {
if (extension.hasOwnProperty(method) && typeof extension[method] === 'function') {
methods.push(method);
Public[method] = extension[method];
}
}
Public.extensions.push({'name' : name, 'methods' : methods});
return Public; // chainable
};
Public.register = function (moduleName, creator) {
Private.modules[moduleName] = {
create: creator,
instance: null
};
return Public; // chainable
};
Public.start = function (moduleName) {
var module = Private.modules[moduleName];
module.instance = module.create(ns.Sandbox);
module.instance.init(null);
return Public; // chainable
};
Public.stop = function (moduleName) {
var module = Private.modules[moduleName];
if (module) {
if (module.instance.hasOwnProperty('destroy') && typeof module.instance.destroy == 'function') {
module.instance.destroy();
}
module.instance = null;
}
return Public; // chainable
};
Public.startAll = function () {
var modules = Private.modules,
moduleName;
for (moduleName in modules) {
if (modules.hasOwnProperty(moduleName)) {
Public.start(moduleName);
}
}
return Public; // chainable
};
Public.stopAll = function () {
var modules = Private.modules,
moduleName;
for (moduleName in modules) {
if (modules.hasOwnProperty(moduleName)) {
Public.stop(moduleName);
}
}
return Public; // chainable
};
return Public;
}());
win.Core = ns.Core = Core;
}(window, document, window.archi)); // return the global object - don't want to assume 'window'
(function (win, Core) {
"use strict";
Core.extend('communication', function (Public, undef) {
var Extension = {},
Private = {};
Private.eventPool = {};
Extension.notify = function (eventInfo) {
// the setTimeout is here to allow for the listeners to catch up on events that are
// fired right away, regardless of the order in which the event listeners / notifiers
// are called. In short it allows you to call the notify method before you call the
// listen method the listen method will still fire.
var eventName = eventInfo.name,
eventData = eventInfo.response,
callback = eventInfo.callback;
win.setTimeout(function () {
var listenerCount = 0, eventLen, e;
if (eventName in Private.eventPool) {
Private.eventPool[eventName].some(function (listener, idx) {
listener.callback.apply(listener.scope, [eventInfo]);
listenerCount++;
});
}
// callback for notifier
if (typeof callback === 'function') {
callback(listenerCount, eventData);
}
}, 0);
return Public; // chainable
};
Extension.listen = function (eventName, callback, scope) {
var i, len, event;
if (!(eventName instanceof Array)) {
eventName = [eventName];
}
for (i = 0, len = eventName.length; i < len; i++) {
event = Private.eventPool[eventName[i]] || [];
event.push({'callback': callback, 'scope': scope || null});
Private.eventPool[eventName[i]] = event;
}
return Public; // chainable
};
Extension.forget = function (eventName, callback) {
var i, j, nLen, eLen, event;
if (!(eventName instanceof Array)) {
eventName = [eventName];
}
for (i = 0, nLen = eventName.length; i < nLen; i += 1) {
event = eventName[i];
if (Private.eventPool[event] && Private.eventPool[event] instanceof Array) {
if (callback === undef) {
Private.eventPool[event] = [];
} else {
// listenOnce was called
Private.eventPool[event] = Private.eventPool[event].filter(function(eventObj){
return eventObj.callback !== callback;
});
}
}
}
return Public; // chainable
};
Extension.listenOnce = function (eventName, callback, scope) {
var fireAndForget = function () {
callback.apply(Public, arguments);
Public.forget(eventName, fireAndForget);
};
Public.listen(eventName, fireAndForget, scope);
return Public; // chainable
};
return Extension;
});
}(window, archi.Core));
</script>
Ready to run.
Test | Ops/sec | |
---|---|---|
jQuery Events |
| ready |
PubSubJS |
| ready |
jQuery PubSub plugin |
| ready |
Pure JS PubSub |
| ready |
Darcy Clarke |
| ready |
Amplify Pub/Sub |
| ready |
Spine Events |
| ready |
Ply Notify/Listen |
| ready |
hyraki |
| ready |
archi |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.