From efdb54ec8a3337eeb0d635a47fc75a84d737340e Mon Sep 17 00:00:00 2001 From: James Hartig Date: Thu, 12 Feb 2015 02:31:25 -0500 Subject: [PATCH] Much smaller/managable fix for jashkenas/backbone#3455 We should eventually pull in their changes but for a hope in actually getting this fix in production I opted to do this instead for now. --- bedrock.js | 18 +++++++++++++++++- test/events.js | 15 ++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/bedrock.js b/bedrock.js index c168e6f..fd5e437 100644 --- a/bedrock.js +++ b/bedrock.js @@ -220,13 +220,29 @@ for (var id in listeningTo) { obj = listeningTo[id]; obj.off(name, callback, this); - if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id]; + if (remove || !eventsLeftForContext(obj, this)) { + delete this._listeningTo[id]; + } } return this; } }; + // Fix memory leak reported in https://github.com/jashkenas/backbone/issues/3453 + // Though their fix is probably better, its a lot larger to try and port right now + function eventsLeftForContext(obj, ctx) { + var i, l, n; + for (n in obj._events) { + for (i = 0, l = obj._events[n].length; i < l; i++) { + if (obj._events[n][i].ctx === ctx) { + return true; + } + } + } + return false; + } + // Space literal reference used to split event strings. var eventSplitter = ' '; diff --git a/test/events.js b/test/events.js index 7418024..98c5213 100644 --- a/test/events.js +++ b/test/events.js @@ -165,21 +165,26 @@ e.trigger("foo"); }); - test("stopListening cleans up references", 8, function() { + test("stopListening cleans up references", 10, function() { var a = _.extend({}, Backbone.Events); var b = _.extend({}, Backbone.Events); var fn = function() {}; - a.listenTo(b, 'event', fn).stopListening(); + b.on('other', fn); + a.listenTo(b, 'all', fn).stopListening(); equal(_.size(a._listeningTo), 0); - equal(_.size(b._events), 0); + equal(_.size(b._events), 1); a.listenTo(b, 'event', fn).stopListening(b); equal(_.size(a._listeningTo), 0); - equal(_.size(b._events), 0); + equal(_.size(b._events), 1); a.listenTo(b, 'event', fn).stopListening(b, 'event'); equal(_.size(a._listeningTo), 0); - equal(_.size(b._events), 0); + equal(_.size(b._events), 1); a.listenTo(b, 'event', fn).stopListening(b, 'event', fn); equal(_.size(a._listeningTo), 0); + a.listenTo(b, 'event', fn).listenTo(b, 'event', fn).stopListening(null, 'event'); + equal(_.size(a._listeningTo), 0); + equal(_.size(b._events), 1); + b.off('other', fn); equal(_.size(b._events), 0); });