Make sure events don't fire after listener is removed.

This patch fixes a problem with a dangling  event listener, which is
called even after it has been removed. This situation can occur when a
listener is removed during an even dispatch.

To fix this problem, the old action is replaced with a NOOP, so that
when the listener is being fired, it is not the old listener but the
NOOP.
This commit is contained in:
R. Merkert 2013-05-07 20:09:40 -04:00
parent f9cd3b532d
commit bbb7acb3f4
2 changed files with 15 additions and 2 deletions

View File

@ -9,6 +9,16 @@ describe('Events', function() {
describe('#fireEvent', function() {
it('makes sure an event is not triggered if a listener is removed during dispatch',function() {
var obj = new Klass(),
spy = sinon.spy();
obj.addEventListener('test', function() { obj.removeEventListener('test',spy); });
obj.addEventListener('test', spy);
obj.fireEvent('test');
expect(spy.called).to.be(false);
});
it('fires all listeners added through #addEventListener', function() {
var obj = new Klass(),
spy1 = sinon.spy(),

View File

@ -75,7 +75,7 @@ L.Mixin.Events = {
var events = this[eventsKey],
contextId = context && L.stamp(context),
i, len, type, listeners, j, indexKey, indexLenKey, typeIndex;
i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed;
types = L.Util.splitWords(types);
@ -97,7 +97,10 @@ L.Mixin.Events = {
if (listeners) {
for (j = listeners.length - 1; j >= 0; j--) {
if ((listeners[j].action === fn) && (!context || (listeners[j].context === context))) {
listeners.splice(j, 1);
removed = listeners.splice(j, 1);
// set the old action to a no-op, because it is possible
// that the listener is being iterated over as part of a dispatch
removed[0].action = L.Util.falseFn;
}
}