Make channel safer about adding/removing listeners during a fire.
Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/commit/e4448110 Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/tree/e4448110 Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/diff/e4448110 Branch: refs/heads/master Commit: e4448110fd2dd9da97c22276dfa1458a71c9f658 Parents: 470ac67 Author: Andrew Grieve <agri...@chromium.org> Authored: Thu Aug 23 23:20:41 2012 -0400 Committer: Andrew Grieve <agri...@chromium.org> Committed: Thu Aug 23 23:35:56 2012 -0400 ---------------------------------------------------------------------- lib/common/channel.js | 14 ++++++++------ test/test.channel.js | 9 +++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/e4448110/lib/common/channel.js ---------------------------------------------------------------------- diff --git a/lib/common/channel.js b/lib/common/channel.js index 7281f1b..e68b9cf 100755 --- a/lib/common/channel.js +++ b/lib/common/channel.js @@ -192,7 +192,6 @@ Channel.prototype.unsubscribe = function(g) { var handler = this.handlers[g]; if (handler) { if (handler.observer_guid) handler.observer_guid=null; - this.handlers[g] = null; delete this.handlers[g]; this.numHandlers--; if (this.events.onUnsubscribe) this.events.onUnsubscribe.call(this); @@ -207,12 +206,15 @@ Channel.prototype.fire = function(e) { var fail = false; this.fired = true; this.fireArgs = arguments; + // Copy the values first so that it is safe to modify it from within + // callbacks. + var toCall = []; for (var item in this.handlers) { - var handler = this.handlers[item]; - if (typeof handler == 'function') { - var rv = (handler.apply(this, arguments)===false); - fail = fail || rv; - } + toCall.push(this.handlers[item]); + } + for (var i = 0; i < toCall.length; ++i) { + var rv = (toCall[i].apply(this, arguments)===false); + fail = fail || rv; } return !fail; } http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/e4448110/test/test.channel.js ---------------------------------------------------------------------- diff --git a/test/test.channel.js b/test/test.channel.js index b485f6f..ae81527 100644 --- a/test/test.channel.js +++ b/test/test.channel.js @@ -233,5 +233,14 @@ describe("channel", function () { c.fire(); expect(count).toEqual(2); }); + it("should not prevent a callback from firing when it is removed during firing.", function() { + var count = 0; + var handler = jasmine.createSpy().andCallFake(function() { count++; c.unsubscribe(handler2); }); + var handler2 = jasmine.createSpy().andCallFake(function() { count++; }); + c.subscribeOnce(handler); + c.subscribeOnce(handler2); + c.fire(); + expect(count).toEqual(2); + }); }); });