Merge pull request #21673 from Snuffleupagus/EventBus-Map-Set

Re-factor the `EventBus` to use Map/Set internally
This commit is contained in:
Tim van der Meij 2026-07-31 19:50:16 +02:00 committed by GitHub
commit 4b4c784a85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -14,6 +14,7 @@
*/ */
import { INTERNAL_EVT, internalOpt } from "./internal_evt.js"; import { INTERNAL_EVT, internalOpt } from "./internal_evt.js";
import { makeSet } from "pdfjs-lib";
const WaitOnType = { const WaitOnType = {
EVENT: "event", EVENT: "event",
@ -72,7 +73,7 @@ async function waitOnEventOrTimeout({ target, name, delay = 0 }) {
* and `off` methods. To raise an event, the `dispatch` method shall be used. * and `off` methods. To raise an event, the `dispatch` method shall be used.
*/ */
class EventBus { class EventBus {
#listeners = Object.create(null); #listeners = new Map();
constructor() { constructor() {
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
@ -101,8 +102,7 @@ class EventBus {
signal.addEventListener("abort", onAbort); signal.addEventListener("abort", onAbort);
} }
const eventListeners = (this.#listeners[eventName] ??= []); this.#listeners.getOrInsertComputed(eventName, makeSet).add({
eventListeners.push({
listener, listener,
internal: options?.internal === INTERNAL_EVT, internal: options?.internal === INTERNAL_EVT,
once: options?.once === true, once: options?.once === true,
@ -116,17 +116,11 @@ class EventBus {
* @param {Object} [options] * @param {Object} [options]
*/ */
off(eventName, listener, options = null) { off(eventName, listener, options = null) {
const eventListeners = this.#listeners[eventName]; const eventListeners = this.#listeners.get(eventName);
if (!eventListeners) { const evt = eventListeners?.keys().find(e => e.listener === listener);
return; if (evt) {
}
for (let i = 0, ii = eventListeners.length; i < ii; i++) {
const evt = eventListeners[i];
if (evt.listener === listener) {
evt.rmAbort?.(); // Ensure that the `AbortSignal` listener is removed. evt.rmAbort?.(); // Ensure that the `AbortSignal` listener is removed.
eventListeners.splice(i, 1); eventListeners.delete(evt);
return;
}
} }
} }
@ -135,14 +129,14 @@ class EventBus {
* @param {Object} data * @param {Object} data
*/ */
dispatch(eventName, data) { dispatch(eventName, data) {
const eventListeners = this.#listeners[eventName]; const eventListeners = this.#listeners.get(eventName);
if (!eventListeners?.length) { if (!eventListeners?.size) {
return; return;
} }
let extListeners; let extListeners;
// Making copy of the listeners array in case if it will be modified // Always create a copy of the listeners in case they are modified
// during dispatch. // during dispatch.
for (const { listener, internal, once } of eventListeners.slice(0)) { for (const { listener, internal, once } of new Set(eventListeners)) {
if (once) { if (once) {
this.off(eventName, listener); this.off(eventName, listener);
} }