Merge pull request #18888 from Snuffleupagus/MessageHandler-AbortSignal

Re-factor the `MessageHandler`-class event handler function
This commit is contained in:
Jonas Jenwald 2024-10-18 17:27:14 +02:00 committed by GitHub
commit c88d3a31cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 90 additions and 66 deletions

View File

@ -1982,7 +1982,7 @@ class PDFPageProxy {
} }
class LoopbackPort { class LoopbackPort {
#listeners = new Set(); #listeners = new Map();
#deferred = Promise.resolve(); #deferred = Promise.resolve();
@ -1992,21 +1992,39 @@ class LoopbackPort {
}; };
this.#deferred.then(() => { this.#deferred.then(() => {
for (const listener of this.#listeners) { for (const [listener] of this.#listeners) {
listener.call(this, event); listener.call(this, event);
} }
}); });
} }
addEventListener(name, listener) { addEventListener(name, listener, options = null) {
this.#listeners.add(listener); let rmAbort = null;
if (options?.signal instanceof AbortSignal) {
const { signal } = options;
if (signal.aborted) {
warn("LoopbackPort - cannot use an `aborted` signal.");
return;
}
const onAbort = () => this.removeEventListener(name, listener);
rmAbort = () => signal.removeEventListener("abort", onAbort);
signal.addEventListener("abort", onAbort);
}
this.#listeners.set(listener, rmAbort);
} }
removeEventListener(name, listener) { removeEventListener(name, listener) {
const rmAbort = this.#listeners.get(listener);
rmAbort?.();
this.#listeners.delete(listener); this.#listeners.delete(listener);
} }
terminate() { terminate() {
for (const [, rmAbort] of this.#listeners) {
rmAbort?.();
}
this.#listeners.clear(); this.#listeners.clear();
} }
} }

View File

@ -69,6 +69,8 @@ function wrapReason(reason) {
} }
class MessageHandler { class MessageHandler {
#messageAC = new AbortController();
constructor(sourceName, targetName, comObj) { constructor(sourceName, targetName, comObj) {
this.sourceName = sourceName; this.sourceName = sourceName;
this.targetName = targetName; this.targetName = targetName;
@ -80,71 +82,74 @@ class MessageHandler {
this.callbackCapabilities = Object.create(null); this.callbackCapabilities = Object.create(null);
this.actionHandler = Object.create(null); this.actionHandler = Object.create(null);
this._onComObjOnMessage = event => { comObj.addEventListener("message", this.#onMessage.bind(this), {
const data = event.data; signal: this.#messageAC.signal,
if (data.targetName !== this.sourceName) { });
return; }
}
if (data.stream) {
this.#processStreamMessage(data);
return;
}
if (data.callback) {
const callbackId = data.callbackId;
const capability = this.callbackCapabilities[callbackId];
if (!capability) {
throw new Error(`Cannot resolve callback ${callbackId}`);
}
delete this.callbackCapabilities[callbackId];
if (data.callback === CallbackKind.DATA) { #onMessage({ data }) {
capability.resolve(data.data); if (data.targetName !== this.sourceName) {
} else if (data.callback === CallbackKind.ERROR) { return;
capability.reject(wrapReason(data.reason)); }
} else { if (data.stream) {
throw new Error("Unexpected callback case"); this.#processStreamMessage(data);
} return;
return; }
if (data.callback) {
const callbackId = data.callbackId;
const capability = this.callbackCapabilities[callbackId];
if (!capability) {
throw new Error(`Cannot resolve callback ${callbackId}`);
} }
const action = this.actionHandler[data.action]; delete this.callbackCapabilities[callbackId];
if (!action) {
throw new Error(`Unknown action from worker: ${data.action}`);
}
if (data.callbackId) {
const cbSourceName = this.sourceName;
const cbTargetName = data.sourceName;
new Promise(function (resolve) { if (data.callback === CallbackKind.DATA) {
resolve(action(data.data)); capability.resolve(data.data);
}).then( } else if (data.callback === CallbackKind.ERROR) {
function (result) { capability.reject(wrapReason(data.reason));
comObj.postMessage({ } else {
sourceName: cbSourceName, throw new Error("Unexpected callback case");
targetName: cbTargetName,
callback: CallbackKind.DATA,
callbackId: data.callbackId,
data: result,
});
},
function (reason) {
comObj.postMessage({
sourceName: cbSourceName,
targetName: cbTargetName,
callback: CallbackKind.ERROR,
callbackId: data.callbackId,
reason: wrapReason(reason),
});
}
);
return;
} }
if (data.streamId) { return;
this.#createStreamSink(data); }
return; const action = this.actionHandler[data.action];
} if (!action) {
action(data.data); throw new Error(`Unknown action from worker: ${data.action}`);
}; }
comObj.addEventListener("message", this._onComObjOnMessage); if (data.callbackId) {
const sourceName = this.sourceName,
targetName = data.sourceName,
comObj = this.comObj;
new Promise(function (resolve) {
resolve(action(data.data));
}).then(
function (result) {
comObj.postMessage({
sourceName,
targetName,
callback: CallbackKind.DATA,
callbackId: data.callbackId,
data: result,
});
},
function (reason) {
comObj.postMessage({
sourceName,
targetName,
callback: CallbackKind.ERROR,
callbackId: data.callbackId,
reason: wrapReason(reason),
});
}
);
return;
}
if (data.streamId) {
this.#createStreamSink(data);
return;
}
action(data.data);
} }
on(actionName, handler) { on(actionName, handler) {
@ -527,7 +532,8 @@ class MessageHandler {
} }
destroy() { destroy() {
this.comObj.removeEventListener("message", this._onComObjOnMessage); this.#messageAC?.abort();
this.#messageAC = null;
} }
} }