Better EventEmitter modify-in-emit
Changed ReallyEmit so that it clones the Array of listeners before processing the emit. Added better tests to make sure that modifying listeners inside event handlers doesn't cause later listeners to be skipped or added.
This commit is contained in:
parent
39f0ef9d4a
commit
e5cbe73a82
@ -182,7 +182,7 @@ process.mixin = function() {
|
||||
var eventsModule = createInternalModule('events', function (exports) {
|
||||
exports.EventEmitter = process.EventEmitter;
|
||||
|
||||
// process.EventEmitter is defined in src/events.cc
|
||||
// process.EventEmitter is defined in src/node_events.cc
|
||||
// process.EventEmitter.prototype.emit() is also defined there.
|
||||
process.EventEmitter.prototype.addListener = function (type, listener) {
|
||||
if (!(listener instanceof Function)) {
|
||||
|
@ -50,7 +50,6 @@ static bool ReallyEmit(Handle<Object> self,
|
||||
Local<Object> events = events_v->ToObject();
|
||||
|
||||
Local<Value> listeners_v = events->Get(event);
|
||||
Local<Function> listener;
|
||||
|
||||
TryCatch try_catch;
|
||||
|
||||
@ -66,7 +65,7 @@ static bool ReallyEmit(Handle<Object> self,
|
||||
}
|
||||
|
||||
} else if (listeners_v->IsArray()) {
|
||||
Local<Array> listeners = Local<Array>::Cast(listeners_v);
|
||||
Local<Array> listeners = Local<Array>::Cast(listeners_v->ToObject()->Clone());
|
||||
|
||||
for (uint32_t i = 0; i < listeners->Length(); i++) {
|
||||
Local<Value> listener_v = listeners->Get(i);
|
||||
|
@ -8,6 +8,7 @@ var e = new events.EventEmitter();
|
||||
function callback1() {
|
||||
callbacks_called.push("callback1");
|
||||
e.addListener("foo", callback2);
|
||||
e.addListener("foo", callback3);
|
||||
e.removeListener("foo", callback1);
|
||||
}
|
||||
|
||||
@ -16,23 +17,39 @@ function callback2() {
|
||||
e.removeListener("foo", callback2);
|
||||
}
|
||||
|
||||
function callback3() {
|
||||
callbacks_called.push("callback3");
|
||||
e.removeListener("foo", callback3);
|
||||
}
|
||||
|
||||
e.addListener("foo", callback1);
|
||||
assert.equal(1, e.listeners("foo").length);
|
||||
|
||||
e.emit("foo");
|
||||
assert.equal(1, e.listeners("foo").length);
|
||||
assert.equal(2, e.listeners("foo").length);
|
||||
assert.deepEqual(["callback1"], callbacks_called);
|
||||
|
||||
e.emit("foo");
|
||||
assert.equal(0, e.listeners("foo").length);
|
||||
assert.deepEqual(["callback1", "callback2"], callbacks_called);
|
||||
assert.deepEqual(["callback1", "callback2", "callback3"], callbacks_called);
|
||||
|
||||
e.emit("foo");
|
||||
assert.equal(0, e.listeners("foo").length);
|
||||
assert.deepEqual(["callback1", "callback2"], callbacks_called);
|
||||
assert.deepEqual(["callback1", "callback2", "callback3"], callbacks_called);
|
||||
|
||||
e.addListener("foo", callback1);
|
||||
e.addListener("foo", callback2);
|
||||
assert.equal(2, e.listeners("foo").length)
|
||||
e.removeAllListeners("foo")
|
||||
assert.equal(0, e.listeners("foo").length)
|
||||
assert.equal(0, e.listeners("foo").length)
|
||||
|
||||
// Verify that removing callbacks while in emit allows emits to propagate to
|
||||
// all listeners
|
||||
callbacks_called = [ ];
|
||||
|
||||
e.addListener("foo", callback2);
|
||||
e.addListener("foo", callback3);
|
||||
assert.equal(2, e.listeners("foo").length)
|
||||
e.emit("foo");
|
||||
assert.deepEqual(["callback2", "callback3"], callbacks_called);
|
||||
assert.equal(0, e.listeners("foo").length)
|
||||
|
Loading…
x
Reference in New Issue
Block a user