A Comparison of JS Publish/Subscribe Approaches
JavaScript performance comparison
Info
A Comparison of JS Publish/Subscribe Approaches
In this comparison I'm trying to focus on event inheritance feature present in PubSubJS and my implementation of the JQuery PubSub plugin.
In most PubSub implementations Subscribers and Publishers have a one to one relationship. This gives them a huge performance benefit, but can be a drawback when building complex decoupled applications as you have to wire every single event. In this comparison I'm looking at a pretty standard GUI like the one on google.com. We have a HEADER region, a tool region to the LEFT, a CONTENT region and a FOOTER. Each one of these regions are dependent on each other using PubSub to communicate. A MANAGER in each region is responsible for Loading/Unloading modules. A typical PubSub message for this application would look something like this:
"/APP/REGION/MODULE/EVENT"
Using a PubSub implementation that allows for inheritance allow us to create a subscriber for "/APP/REGION" that would listen to ALL events that occur within this region. Using the simpler implementations we would have to publish two events, one for the module and one for the region.
In this example each PubSub implementation has 4 subscribers. One for APP, REGION, MODULE and EVENT each. PubSubJS and JQuery Subscriber may invoke all four subscriber callbacks by a single publication to app/region/module/event where as the rest each has to publish 4 events.
More info
- publish/subscribe on Wikipedia.
- The Many Faces of Publish/Subscribe.
Compared:
Preparation code
<script src="https://raw.github.com/jrburke/requirejs/master/require.js" type="text/javascript">
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="https://raw.github.com/pmelander/Subtopic/master/jquery-subtopic.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/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 type="text/javascript">
window.iter = 0
window.callback = function() {};
window.payload = {
somekey: 'some value'
};
var topics = {};
jQuery.Topic = function( id ) {
var callbacks,
method,
topic = id && topics[ id ];
if ( !topic ) {
callbacks = jQuery.Callbacks();
topic = {
publish: callbacks.fire,
subscribe: callbacks.add,
unsubscribe: callbacks.remove
};
if ( id ) {
topics[ id ] = topic;
}
}
return topic;
};
jQuery.Topic('/app').subscribe(callback);
jQuery.Topic('/app/region').subscribe(callback);
jQuery.Topic('/app/region/module').subscribe(callback);
jQuery.Topic('/app/region/module/event').subscribe(callback);
jQuery(function() {
jQuery(window).on('/app', callback);
jQuery(window).on('/app/region', callback);
jQuery(window).on('/app/region/module', callback);
jQuery(window).on('/app/region/module/event', callback);
// PubSubJS doesn't expose any globals when in AMD environment
require(['https://raw.github.com/mroderick/PubSubJS/master/src/pubsub.js'], function(PubSub){
// add PubSub to global scope, to not pay the cost in every execution of the tests
window.PubSub = PubSub;
PubSub.subscribe('app', callback);
PubSub.subscribe('app.region', callback);
PubSub.subscribe('app.region.module', callback);
PubSub.subscribe('app.region.module.event', callback);
});
jQuery.subscribe('/app', callback);
jQuery.subscribe('/app/region', callback);
jQuery.subscribe('/app/region/module', callback);
jQuery.subscribe('/app/region/module/event', callback);
Events.subscribe('/app', callback);
Events.subscribe('/app/region', callback);
Events.subscribe('/app/region/module', callback);
Events.subscribe('/app/region/module/event', callback);
amplify.subscribe('/app', callback);
amplify.subscribe('/app/region', callback);
amplify.subscribe('/app/region/module', callback);
amplify.subscribe('/app/region/module/event', callback);
Spine.bind('/app', callback);
Spine.bind('/app/region', callback);
Spine.bind('/app/region/module', callback);
Spine.bind('/app/region/module/event', callback);
Ply.core.listen('/app', callback);
Ply.core.listen('/app/region', callback);
Ply.core.listen('/app/region/module', callback);
Ply.core.listen('/app/region/module/event', callback);
require(["https://raw.github.com/jkroso/Observer/less-function-calls/dist/Observer.min.js", "https://raw.github.com/jkroso/Observer/master/dist/Observer.min.js"], function(Observer1, Observer2) {
window.recursive= new Observer1();
window.iterative= new Observer2();
recursive.subscribe('app', callback);
recursive.subscribe('app.region', callback);
recursive.subscribe('app.region.module', callback);
recursive.subscribe('app.region.module.event', callback);
iterative.on('app', callback);
iterative.on('app.region', callback);
iterative.on('app.region.module', callback);
iterative.on('app.region.module.event', callback);
});
});
</script>
Preparation code output
Test runner
Warning! For accurate results, please disable Firebug before running the tests. (Why?)
Java applet disabled.
| Test | Ops/sec | |
|---|---|---|
jQuery Events |
|
pending… |
PubSubJS - async |
|
pending… |
PubSubJS - sync |
|
pending… |
Pure JS PubSub |
|
pending… |
Amplify Pub/Sub |
|
pending… |
Spine Events |
|
pending… |
Ply Notify/Listen |
|
pending… |
Recursive Observer |
|
pending… |
Iterative Observer |
|
pending… |
Subtopic for jQuery |
|
pending… |
jQuery Callbacks |
|
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:
- Revision 1: published by Morgan Roderick
- Revision 3: published by Morgan Roderick
- Revision 4: published
- Revision 5: published by Stephen Crosby
- Revision 6: published by Andrew Betts
- Revision 8: published
- Revision 11: published
- Revision 12: published by Morgan Roderick
- Revision 18: published
- Revision 19: published
- Revision 20: published
- Revision 21: published
- Revision 22: published by Richard and last updated
- Revision 24: published by Hiroshi Kuwabara
- Revision 25: published
- Revision 26: published by s0ber
- Revision 30: published by Jakeb
- Revision 31: published by Jakeb
- Revision 34: published by pmelande
- Revision 36: published by pmelande
- Revision 37: published by pmelande
- Revision 39: published by Jakeb
- Revision 40: published by Jakeb
- Revision 41: published by pmelande
- Revision 43: published by Morgan Roderick
- Revision 44: published by Jakeb
- Revision 47: published by asyraf
- Revision 50: published by pmelande
- Revision 51: published by pmelande
- Revision 52: published by Jakeb
- Revision 53: published
- Revision 54: published
- Revision 55: published
- Revision 56: published by Anas Nakawa
- Revision 57: published
- Revision 58: published
- Revision 59: published by Burke
- Revision 60: published by Tobias Haustein
- Revision 62: published by vlazar
- Revision 64: published by Stuart
- Revision 66: published by Brandon Papworth
- Revision 67: published
- Revision 68: published
- Revision 69: published
- Revision 70: published
- Revision 73: published
- Revision 74: published
- Revision 75: published by Wojciech Dłubacz
- Revision 76: published
- Revision 77: published
- Revision 78: published by Wojciech Dłubacz
- Revision 79: published
- Revision 80: published by Sparda
- Revision 82: published
- Revision 83: published by Bruno
- Revision 85: published
- Revision 86: published
- Revision 87: published
- Revision 88: published
- Revision 89: published
- Revision 90: published
- Revision 91: published
- Revision 92: published by Caleb Gilbert
- Revision 93: published
- Revision 94: published
- Revision 95: published
- Revision 97: published by Brandon Papworth
- Revision 99: published
- Revision 100: published
- Revision 101: published
- Revision 102: published
0 comments