Backbone Events

JavaScript performance comparison

Revision 36 of this test case created by stefan and last updated

Preparation code

<script src='//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js'></script>
<script src='//rawgithub.com/wycats/handlebars.js/1.0.0-rc.3/dist/handlebars.runtime.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/1.0.0/backbone-min.js'></script>
<script>
  var backboneEvents = Backbone.Events;
</script>
<script src="//builds.emberjs.com.s3.amazonaws.com/ember-1.0.0-rc.3.min.js"></script>
<script>
  var emberEvents = Ember.Object.extend(Ember.Evented);
</script>
<script src='//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js?alt=1'></script>
<script>
  var altEvents = 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);
        }
        };

    altEvents.bind = altEvents.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;
    };

    altEvents.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 altObject = _.extend({x:0}, altEvents);
    var backboneObject = _.extend({x:0}, backboneEvents);
    var emberObject = emberEvents.create({x:0});
    var jqueryObject = $({x:0});
   
    var numEvents = 3;
    var numListeners = 100;
    var objs = [altObject, backboneObject, emberObject, jqueryObject];
   
    _.times(numEvents, function(n) {
      _.times(numListeners, function() {
        _.each(objs, function(obj) {
          obj.on('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
Backbone
for (var i = 0; i < numEvents; i++) {
  backboneObject.trigger('event' + i, 1, 2, 3);
}
pending…
Backbone Alt
for (var i = 0; i < numEvents; i++) {
  altObject.trigger('event' + i, 1, 2, 3);
}
pending…
Ember
for (var i = 0; i < numEvents; i++) {
  emberObject.trigger('event' + i, 1, 2, 3);
}
pending…
jQuery
for (var i = 0; i < numEvents; i++) {
  jqueryObject.triggerHandler('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