Skip to content

Commit 4ef0c0b

Browse files
committed
fixup
1 parent 26c85fa commit 4ef0c0b

File tree

1 file changed

+167
-110
lines changed

1 file changed

+167
-110
lines changed

lib/internal/event_target.js

Lines changed: 167 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,8 @@ class EventTarget {
552552
initEventTarget(this);
553553
}
554554

555+
#fastHandlers = new Map();
556+
555557
[kNewListener](size, type, listener, once, capture, passive, weak) {
556558
if (this[kMaxEventTargetListeners] > 0 &&
557559
size > this[kMaxEventTargetListeners] &&
@@ -572,6 +574,27 @@ class EventTarget {
572574
}
573575
[kRemoveListener](size, type, listener, capture) {}
574576

577+
#toSlowMode () {
578+
if (this.#fastHandlers == null) {
579+
return;
580+
}
581+
582+
const handlers = this.#fastHandlers;
583+
584+
this.#fastHandlers = null;
585+
for (const [type, listeners] of handlers) {
586+
if (listeners == null) {
587+
// Do nothing..
588+
} else if (typeof listeners === 'function') {
589+
this.addEventListener(type, listeners);
590+
} else {
591+
for (const listener of listeners) {
592+
this.addEventListener(type, listener);
593+
}
594+
}
595+
}
596+
}
597+
575598
/**
576599
* @callback EventTargetCallback
577600
* @param {Event} event
@@ -644,45 +667,60 @@ class EventTarget {
644667
}
645668
}
646669

647-
type = webidl.converters.DOMString(type);
670+
if (options === kEmptyObject && this.#fastHandlers != null) {
671+
const entry = this.#fastHandlers.get(type);
672+
if (entry == null) {
673+
this.#fastHandlers.set(type, listener);
674+
} else if (typeof entry === 'function') {
675+
this.#fastHandlers.set(type, new Set([entry, listener]));
676+
} else {
677+
entry.add(listener);
678+
}
679+
} else {
680+
if (this.#fastHandlers != null) {
681+
this.#toSlowMode();
682+
}
648683

649-
let root = this[kEvents].get(type);
684+
type = webidl.converters.DOMString(type);
685+
686+
let root = this[kEvents].get(type);
687+
688+
if (root === undefined) {
689+
root = { size: 1, next: undefined, resistStopPropagation: Boolean(resistStopPropagation) };
690+
// This is the first handler in our linked list.
691+
new Listener(this, type, root, listener, once, capture, passive,
692+
isNodeStyleListener, weak, resistStopPropagation);
693+
this[kNewListener](
694+
root.size,
695+
type,
696+
listener,
697+
once,
698+
capture,
699+
passive,
700+
weak);
701+
this[kEvents].set(type, root);
702+
return;
703+
}
650704

651-
if (root === undefined) {
652-
root = { size: 1, next: undefined, resistStopPropagation: Boolean(resistStopPropagation) };
653-
// This is the first handler in our linked list.
654-
new Listener(this, type, root, listener, once, capture, passive,
655-
isNodeStyleListener, weak, resistStopPropagation);
656-
this[kNewListener](
657-
root.size,
658-
type,
659-
listener,
660-
once,
661-
capture,
662-
passive,
663-
weak);
664-
this[kEvents].set(type, root);
665-
return;
666-
}
705+
let handler = root.next;
706+
let previous = root;
667707

668-
let handler = root.next;
669-
let previous = root;
708+
// We have to walk the linked list to see if we have a match
709+
while (handler !== undefined && !handler.same(listener, capture)) {
710+
previous = handler;
711+
handler = handler.next;
712+
}
670713

671-
// We have to walk the linked list to see if we have a match
672-
while (handler !== undefined && !handler.same(listener, capture)) {
673-
previous = handler;
674-
handler = handler.next;
675-
}
714+
if (handler !== undefined) { // Duplicate! Ignore
715+
return;
716+
}
676717

677-
if (handler !== undefined) { // Duplicate! Ignore
678-
return;
718+
new Listener(this, type, previous, listener, once, capture, passive,
719+
isNodeStyleListener, weak, resistStopPropagation);
720+
root.size++;
721+
root.resistStopPropagation ||= Boolean(resistStopPropagation);
722+
this[kNewListener](root.size, type, listener, once, capture, passive, weak);
679723
}
680-
681-
new Listener(this, type, previous, listener, once, capture, passive,
682-
isNodeStyleListener, weak, resistStopPropagation);
683-
root.size++;
684-
root.resistStopPropagation ||= Boolean(resistStopPropagation);
685-
this[kNewListener](root.size, type, listener, once, capture, passive, weak);
686724
}
687725

688726
/**
@@ -700,24 +738,39 @@ class EventTarget {
700738
if (!validateEventListener(listener))
701739
return;
702740

703-
type = webidl.converters.DOMString(type);
704-
const capture = options?.capture === true;
705-
706-
const root = this[kEvents].get(type);
707-
if (root === undefined || root.next === undefined)
708-
return;
741+
if (options === kEmptyObject && this.#fastHandlers != null) {
742+
const entry = this.#fastHandlers.get(type);
743+
if (entry == null) {
744+
// Do nothing
745+
} else if (entry === listener) {
746+
this.#fastHandlers.delete(type);
747+
} else {
748+
entry.delete(listener);
749+
}
750+
} else {
751+
if (this.#fastHandlers != null) {
752+
this.#toSlowMode();
753+
}
709754

710-
let handler = root.next;
711-
while (handler !== undefined) {
712-
if (handler.same(listener, capture)) {
713-
handler.remove();
714-
root.size--;
715-
if (root.size === 0)
716-
this[kEvents].delete(type);
717-
this[kRemoveListener](root.size, type, listener, capture);
718-
break;
755+
type = webidl.converters.DOMString(type);
756+
const capture = options?.capture === true;
757+
758+
const root = this[kEvents].get(type);
759+
if (root === undefined || root.next === undefined)
760+
return;
761+
762+
let handler = root.next;
763+
while (handler !== undefined) {
764+
if (handler.same(listener, capture)) {
765+
handler.remove();
766+
root.size--;
767+
if (root.size === 0)
768+
this[kEvents].delete(type);
769+
this[kRemoveListener](root.size, type, listener, capture);
770+
break;
771+
}
772+
handler = handler.next;
719773
}
720-
handler = handler.next;
721774
}
722775
}
723776

@@ -764,77 +817,81 @@ class EventTarget {
764817
}
765818

766819
[kHybridDispatch](nodeValue, type, event) {
767-
const createEvent = () => {
768-
if (event === undefined) {
769-
event = this[kCreateEvent](nodeValue, type);
820+
if (this.#fastHandlers != null) {
821+
// XXX: Implement
822+
} else {
823+
const createEvent = () => {
824+
if (event === undefined) {
825+
event = this[kCreateEvent](nodeValue, type);
826+
event[kTarget] = this;
827+
event[kIsBeingDispatched] = true;
828+
}
829+
return event;
830+
};
831+
if (event !== undefined) {
770832
event[kTarget] = this;
771833
event[kIsBeingDispatched] = true;
772834
}
773-
return event;
774-
};
775-
if (event !== undefined) {
776-
event[kTarget] = this;
777-
event[kIsBeingDispatched] = true;
778-
}
779-
780-
const root = this[kEvents].get(type);
781-
if (root === undefined || root.next === undefined) {
782-
if (event !== undefined)
783-
event[kIsBeingDispatched] = false;
784-
return true;
785-
}
786-
787-
let handler = root.next;
788-
let next;
789835

790-
const iterationCondition = () => {
791-
if (handler === undefined) {
792-
return false;
793-
}
794-
return root.resistStopPropagation || handler.passive || event?.[kStop] !== true;
795-
};
796-
while (iterationCondition()) {
797-
// Cache the next item in case this iteration removes the current one
798-
next = handler.next;
799-
800-
if (handler.removed || (event?.[kStop] === true && !handler.resistStopPropagation)) {
801-
// Deal with the case an event is removed while event handlers are
802-
// Being processed (removeEventListener called from a listener)
803-
// And the case of event.stopImmediatePropagation() being called
804-
// For events not flagged as resistStopPropagation
805-
handler = next;
806-
continue;
807-
}
808-
if (handler.once) {
809-
handler.remove();
810-
root.size--;
811-
const { listener, capture } = handler;
812-
this[kRemoveListener](root.size, type, listener, capture);
836+
const root = this[kEvents].get(type);
837+
if (root === undefined || root.next === undefined) {
838+
if (event !== undefined)
839+
event[kIsBeingDispatched] = false;
840+
return true;
813841
}
814842

815-
try {
816-
let arg;
817-
if (handler.isNodeStyleListener) {
818-
arg = nodeValue;
819-
} else {
820-
arg = createEvent();
843+
let handler = root.next;
844+
let next;
845+
846+
const iterationCondition = () => {
847+
if (handler === undefined) {
848+
return false;
821849
}
822-
const callback = handler.weak ?
823-
handler.callback.deref() : handler.callback;
824-
let result;
825-
if (callback) {
826-
result = FunctionPrototypeCall(callback, this, arg);
827-
if (!handler.isNodeStyleListener) {
828-
arg[kIsBeingDispatched] = false;
850+
return root.resistStopPropagation || handler.passive || event?.[kStop] !== true;
851+
};
852+
while (iterationCondition()) {
853+
// Cache the next item in case this iteration removes the current one
854+
next = handler.next;
855+
856+
if (handler.removed || (event?.[kStop] === true && !handler.resistStopPropagation)) {
857+
// Deal with the case an event is removed while event handlers are
858+
// Being processed (removeEventListener called from a listener)
859+
// And the case of event.stopImmediatePropagation() being called
860+
// For events not flagged as resistStopPropagation
861+
handler = next;
862+
continue;
863+
}
864+
if (handler.once) {
865+
handler.remove();
866+
root.size--;
867+
const { listener, capture } = handler;
868+
this[kRemoveListener](root.size, type, listener, capture);
869+
}
870+
871+
try {
872+
let arg;
873+
if (handler.isNodeStyleListener) {
874+
arg = nodeValue;
875+
} else {
876+
arg = createEvent();
829877
}
878+
const callback = handler.weak ?
879+
handler.callback.deref() : handler.callback;
880+
let result;
881+
if (callback) {
882+
result = FunctionPrototypeCall(callback, this, arg);
883+
if (!handler.isNodeStyleListener) {
884+
arg[kIsBeingDispatched] = false;
885+
}
886+
}
887+
if (result !== undefined && result !== null)
888+
addCatch(result);
889+
} catch (err) {
890+
emitUncaughtException(err);
830891
}
831-
if (result !== undefined && result !== null)
832-
addCatch(result);
833-
} catch (err) {
834-
emitUncaughtException(err);
835-
}
836892

837-
handler = next;
893+
handler = next;
894+
}
838895
}
839896

840897
if (event !== undefined)

0 commit comments

Comments
 (0)