Peter Higgins Pubsub vs tiny-pubsub (v14)

Revision 14 of this benchmark created on


Preparation HTML

<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js">
</script>
<script>
  /*    

 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

function EventTarget(){
    this._listeners = {};
}

EventTarget.prototype = {

    constructor: EventTarget,

    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;
                }
            }
        }
    }
};

</script>

Setup

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_" + i, function() {});
    }

Test runner

Ready to run.

Testing in
TestOps/sec
Peter Higgins
$.publish('topic_300');
ready
Tiny Pubsub
$.pub('topic_300');
ready
Amplify
amplify.publish('topic_300');
ready
Nicholas C. Zakas JS Custom Events
target.fire({ type: "topic_300" });
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.