Backbone Events

JavaScript performance comparison

Revision 40 of this test case created by Paul Miller

Preparation code

<script src='//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js'></script>
<script src='//cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.underscore.js'></script>
<script src='//cdnjs.cloudflare.com/ajax/libs/backbone.js/0.5.2/backbone-min.js'></script>
<script>var bb053Events = Backbone.Events;</script>
<script src='//cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js'></script>
<script>var bb092Events = Backbone.Events;</script>
<script src='//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js'></script>
<script>var bb100Events = Backbone.Events;</script>
<script src="https://gist.github.com/paulmillr/ee031a6e4ed5956afc90/raw/90fd4880a4ce3c4b3e4ff1b0c70a65e6cfe611e0/exoskel.js"></script>
<script>var exosEvents = Exoskeleton.Events;</script>
<script src='//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js?alt=1'></script>
<script>
var bbAltEvents = Backbone.Events;

(function() {
  var undefined,
      eventSplitter = /\s+/,
      reThis = /\bthis\b/,
      slice = Array.prototype.slice;

  var eventsApi = function(obj, action, name, rest) {
    if (!name) return true;

    if (typeof name === 'object') {
      for (var key in name) {
        obj[action].apply(obj, [key, name[key]].concat(rest));
      }
      return false;
    }
    if (eventSplitter.test(name)) {
      var names = name.split(eventSplitter);
      for (var i = 0, l = names.length; i < l; i++) {
        obj[action].apply(obj, [names[i]].concat(rest));
      }
      return false;
    }
    return true;
  };

  var triggerEvents = function(events, args) {
    var cb, ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
    switch (args.length) {
      case 0: while (++i < l)
        (ev = events[i],
         cb = ev.callback,
         ev.bind ? cb.call(ev.ctx) : cb());
        return;
      case 1: while (++i < l)
        (ev = events[i],
         cb = ev.callback,
         ev.bind ? cb.call(ev.ctx, a1) : cb(a1));
        return;
      case 2: while (++i < l)
        (ev = events[i],
         cb = ev.callback,
         ev.bind ? cb.call(ev.ctx, a1, a2) : cb(a1, a2));
        return;
      case 3: while (++i < l)
        (ev = events[i],
         cb = ev.callback,
         ev.bind ? cb.call(ev.ctx, a1, a2, a3) : cb(a1, a2, a3));
        return;
      default: while (++i < l)
        (ev = events[i]).callback.apply(ev.ctx, args);
    }
  };

  bbAltEvents.bind = bbAltEvents.on = function(name, callback, context) {
    if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
    this._events || (this._events = {});
    var events = this._events[name] || (this._events[name] = []);
    var ctx = reThis.test(callback) ? context || this : undefined;
    events.push({callback: callback, context: context, ctx: ctx, bind: ctx !== undefined});
    return this;
  };

  bbAltEvents.trigger = function(name) {
    if (!this._events) return this;
    var args = slice.call(arguments, 1);
    if (!eventsApi(this, 'trigger', name, args)) return this;
    var events = this._events[name];
    var allEvents = this._events.all;
    if (events) triggerEvents(events, args);
    if (allEvents) triggerEvents(allEvents, arguments);
    return this;
  };
}());
</script>
<script>
Benchmark.prototype.setup = function() {
    var jq = jQuery({});
    var bb053 = _.extend({x:0}, bb053Events);
    var bb092 = _.extend({x:0}, bb092Events);
    var bb100 = _.extend({x:0}, bb100Events);
    var bbAlt = _.extend({x:0}, bbAltEvents);
    var exos = _.extend({x:0}, exosEvents);
   
    var numEvents = 3;
    var numListeners = 100;
    var objs = [jq, bb053, bb092, bb100, bbAlt, exos];
   
    _.times(numEvents, function (n) {
      _.times(numListeners, function () {
        _.each(objs, function(obj) {
          obj.bind('event' + n, function() { obj.x++; });
        });
      });
    });
};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
jQuery 1.9.1
for (var i = 0; i < numEvents; i++) {
  jq.triggerHandler('event' + i, [1, 2, 3]);
}
pending…
Backbone 0.5.3
for (var i = 0; i < numEvents; i++) {
  bb053.trigger('event' + i, 1, 2, 3);
}
pending…
Backbone 0.9.2
for (var i = 0; i < numEvents; i++) {
  bb092.trigger('event' + i, 1, 2, 3);
}
pending…
Backbone 1.0.0
for (var i = 0; i < numEvents; i++) {
  bb100.trigger('event' + i, 1, 2, 3);
}
pending…
Backbone Alt
for (var i = 0; i < numEvents; i++) {
  bbAlt.trigger('event' + i, 1, 2, 3);
}
pending…
Exoskeleton
for (var i = 0; i < numEvents; i++) {
  exos.trigger('event' + i, 1, 2, 3);
}
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:

0 comments

Add a comment