Skip to content

Commit 1fb0954

Browse files
lpincaBethGriggs
authored andcommitted
events: allow an event to be dispatched multiple times
Use a different flag to prevent recursive dispatching. PR-URL: #39395 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 6f2989c commit 1fb0954

2 files changed

Lines changed: 43 additions & 5 deletions

File tree

‎lib/internal/event_target.js‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const {
4747
}=EventEmitter;
4848

4949
constkEvents=Symbol('kEvents');
50+
constkIsBeingDispatched=Symbol('kIsBeingDispatched');
5051
constkStop=Symbol('kStop');
5152
constkTarget=Symbol('kTarget');
5253
constkHandlers=Symbol('khandlers');
@@ -105,6 +106,7 @@ class Event {
105106
configurable: false
106107
});
107108
this[kTarget]=null;
109+
this[kIsBeingDispatched]=false;
108110
}
109111

110112
[customInspectSymbol](depth,options){
@@ -151,12 +153,12 @@ class Event {
151153
// These are not supported in Node.js and are provided purely for
152154
// API completeness.
153155

154-
composedPath(){returnthis[kTarget] ? [this[kTarget]] : [];}
156+
composedPath(){returnthis[kIsBeingDispatched] ? [this[kTarget]] : [];}
155157
getreturnValue(){return!this.defaultPrevented;}
156158
getbubbles(){returnthis[kBubbles];}
157159
getcomposed(){returnthis[kComposed];}
158160
geteventPhase(){
159-
returnthis[kTarget] ? Event.AT_TARGET : Event.NONE;
161+
returnthis[kIsBeingDispatched] ? Event.AT_TARGET : Event.NONE;
160162
}
161163
getcancelBubble(){returnthis[kPropagationStopped];}
162164
setcancelBubble(value){
@@ -397,7 +399,7 @@ class EventTarget {
397399
if(!isEventTarget(this))
398400
thrownewERR_INVALID_THIS('EventTarget');
399401

400-
if(event[kTarget]!==null)
402+
if(event[kIsBeingDispatched])
401403
thrownewERR_EVENT_RECURSION(event.type);
402404

403405
this[kHybridDispatch](event,event.type,event);
@@ -410,11 +412,14 @@ class EventTarget {
410412
if(event===undefined){
411413
event=this[kCreateEvent](nodeValue,type);
412414
event[kTarget]=this;
415+
event[kIsBeingDispatched]=true;
413416
}
414417
returnevent;
415418
};
416-
if(event!==undefined)
419+
if(event!==undefined){
417420
event[kTarget]=this;
421+
event[kIsBeingDispatched]=true;
422+
}
418423

419424
constroot=this[kEvents].get(type);
420425
if(root===undefined||root.next===undefined)
@@ -453,6 +458,9 @@ class EventTarget {
453458
letresult;
454459
if(callback){
455460
result=FunctionPrototypeCall(callback,this,arg);
461+
if(!handler.isNodeStyleListener){
462+
arg[kIsBeingDispatched]=false;
463+
}
456464
}
457465
if(result!==undefined&&result!==null)
458466
addCatch(result);
@@ -464,7 +472,7 @@ class EventTarget {
464472
}
465473

466474
if(event!==undefined)
467-
event[kTarget]=undefined;
475+
event[kIsBeingDispatched]=false;
468476
}
469477

470478
[kCreateEvent](nodeValue,type){

‎test/parallel/test-eventtarget.js‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,36 @@ let asyncTest = Promise.resolve();
162162
eventTarget.dispatchEvent(ev);
163163
}
164164

165+
{
166+
// Same event dispatched multiple times.
167+
constevent=newEvent('foo');
168+
consteventTarget1=newEventTarget();
169+
consteventTarget2=newEventTarget();
170+
171+
eventTarget1.addEventListener('foo',common.mustCall((event)=>{
172+
strictEqual(event.eventPhase,Event.AT_TARGET);
173+
strictEqual(event.target,eventTarget1);
174+
deepStrictEqual(event.composedPath(),[eventTarget1]);
175+
}));
176+
177+
eventTarget2.addEventListener('foo',common.mustCall((event)=>{
178+
strictEqual(event.eventPhase,Event.AT_TARGET);
179+
strictEqual(event.target,eventTarget2);
180+
deepStrictEqual(event.composedPath(),[eventTarget2]);
181+
}));
182+
183+
eventTarget1.dispatchEvent(event);
184+
strictEqual(event.eventPhase,Event.NONE);
185+
strictEqual(event.target,eventTarget1);
186+
deepStrictEqual(event.composedPath(),[]);
187+
188+
189+
eventTarget2.dispatchEvent(event);
190+
strictEqual(event.eventPhase,Event.NONE);
191+
strictEqual(event.target,eventTarget2);
192+
deepStrictEqual(event.composedPath(),[]);
193+
}
194+
165195
{
166196
consteventTarget=newEventTarget();
167197
constevent=newEvent('foo',{cancelable: true});

0 commit comments

Comments
 (0)