diff --git a/lib/internal/event_target.js b/lib/internal/event_target.js index 8c4ea11a14ed8b..3024bbfc7eec3f 100644 --- a/lib/internal/event_target.js +++ b/lib/internal/event_target.js @@ -5,7 +5,6 @@ const { Error, Map, Object, - Set, Symbol, NumberIsNaN, SymbolToStringTag, @@ -186,7 +185,6 @@ class Listener { class EventTarget { [kEvents] = new Map(); - #emitting = new Set(); [kNewListener](size, type, listener, once, capture, passive) {} [kRemoveListener](size, type, listener, capture) {} @@ -257,9 +255,8 @@ class EventTarget { throw new ERR_INVALID_ARG_TYPE('event', 'Event', event); } - if (this.#emitting.has(event.type) || - event[kTarget] !== null) { - throw new ERR_EVENT_RECURSION(event.type); + if (event[kTarget] !== undefined) { + throw new ERR_EVENT_RECURSION(event); } const root = this[kEvents].get(event.type); @@ -267,7 +264,6 @@ class EventTarget { return true; event[kTarget] = this; - this.#emitting.add(event.type); let handler = root.next; let next; @@ -293,7 +289,6 @@ class EventTarget { handler = next; } - this.#emitting.delete(event.type); event[kTarget] = undefined; return event.defaultPrevented === true ? false : true; diff --git a/test/parallel/test-eventtarget.js b/test/parallel/test-eventtarget.js index 3e652e1e3396b4..c1ed4cadcaf2d8 100644 --- a/test/parallel/test-eventtarget.js +++ b/test/parallel/test-eventtarget.js @@ -15,7 +15,7 @@ const { throws, } = require('assert'); -const { once } = require('events'); +const { once, on } = require('events'); // The globals are defined. ok(Event); @@ -69,6 +69,24 @@ ok(EventTarget); const ev = new Event('foo', {}, {}); strictEqual(ev.type, 'foo'); } +{ + const ev = new Event('foo'); + strictEqual(ev.cancelBubble, false); + ev.cancelBubble = true; + strictEqual(ev.cancelBubble, true); +} +{ + const ev = new Event('foo'); + strictEqual(ev.cancelBubble, false); + ev.stopPropagation(); + strictEqual(ev.cancelBubble, true); +} +{ + const ev = new Event('foo'); + strictEqual(ev.cancelBubble, false); + ev.cancelBubble = 'some-truthy-value'; + strictEqual(ev.cancelBubble, true); +} { const ev = new Event('foo', { cancelable: true }); strictEqual(ev.type, 'foo'); @@ -271,10 +289,10 @@ ok(EventTarget); { const eventTarget = new EventTarget(); - + const event = new Event('foo'); // Once handler only invoked once - const ev = common.mustCall((event) => { - throws(() => eventTarget.dispatchEvent(new Event('foo')), { + const ev = common.mustCall(() => { + throws(() => eventTarget.dispatchEvent(event), { code: 'ERR_EVENT_RECURSION' }); }); @@ -282,7 +300,7 @@ ok(EventTarget); // Errors in a handler won't stop calling the others. eventTarget.addEventListener('foo', ev); - eventTarget.dispatchEvent(new Event('foo')); + eventTarget.dispatchEvent(event); } { @@ -439,3 +457,45 @@ ok(EventTarget); const event = new Event(''); strictEqual(event.toString(), '[object Event]'); } +{ + const target = new EventTarget(); + const ev = new Event('toString'); + const fn = common.mustCall((event) => strictEqual(event.type, 'toString')); + target.addEventListener('toString', fn); + target.dispatchEvent(ev); +} +{ + const target = new EventTarget(); + const ev = new Event('__proto__'); + const fn = common.mustCall((event) => strictEqual(event.type, '__proto__')); + target.addEventListener('__proto__', fn); + target.dispatchEvent(ev); +} + +(async () => { + // test NodeEventTarget async-iterability + const emitter = new NodeEventTarget(); + const event = new Event('foo'); + const interval = setInterval(() => emitter.dispatchEvent(event), 0); + let count = 0; + for await (const [ item ] of on(emitter, 'foo')) { + count++; + strictEqual(item.type, 'foo'); + if (count > 5) { + break; + } + } + clearInterval(interval); +})().then(common.mustCall()); +{ + const target = new EventTarget(); + const event = new Event('foo'); + let callCount = 0; + target.addEventListener('foo', common.mustCall(() => { + callCount++; + if (callCount < 5) { + target.dispatchEvent(new Event('foo')); + } + }, 5)); + target.dispatchEvent(event); +}