From 10dabe15e73ec89d1ff1c23be909766223b09c28 Mon Sep 17 00:00:00 2001 From: fallenoak Date: Sat, 6 Jan 2024 16:03:19 -0600 Subject: [PATCH] chore(worker): eliminate side effects from constructors --- src/lib/worker/SceneWorker.ts | 24 -------------- src/lib/worker/SceneWorkerController.ts | 43 ++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/lib/worker/SceneWorker.ts b/src/lib/worker/SceneWorker.ts index f925707..a11390a 100644 --- a/src/lib/worker/SceneWorker.ts +++ b/src/lib/worker/SceneWorker.ts @@ -2,32 +2,17 @@ import { RESPONSE_STATUS } from './const.js'; import { WorkerRequest, WorkerResponse } from './types.js'; class SceneWorker { - #initialized = false; - #initializing: Promise; - #initializingResolve: (value?: any) => void; - #initializingReject: (reason?: any) => void; - constructor() { self.addEventListener('message', (event: MessageEvent) => { const request = event.data; this.#handleRequest(request).catch((error: Error) => this.#handleError(request, error)); }); - - this.#initializing = new Promise((resolve, reject) => { - this.#initializingResolve = resolve; - this.#initializingReject = reject; - }); } initialize(...args: any[]) {} async #handleRequest(request: WorkerRequest) { - // Hold other requests back until initialize is handled - if (!this.#initialized && request.func !== 'initialize') { - await this.#initializing; - } - const func = this[request.func]; if (!func) { throw new Error(`Invalid function name: ${request.func}`); @@ -47,10 +32,6 @@ class SceneWorker { } #handleError(request: WorkerRequest, error: Error) { - if (!this.#initialized && request.func === 'initialize') { - this.#initializingReject(error); - } - const response: WorkerResponse = { id: request.id, status: RESPONSE_STATUS.STATUS_ERROR, @@ -61,11 +42,6 @@ class SceneWorker { } #handleSuccess(request: WorkerRequest, value: any, transfer: Transferable[] = []) { - if (!this.#initialized && request.func === 'initialize') { - this.#initialized = true; - this.#initializingResolve(); - } - const response: WorkerResponse = { id: request.id, status: RESPONSE_STATUS.STATUS_SUCCESS, diff --git a/src/lib/worker/SceneWorkerController.ts b/src/lib/worker/SceneWorkerController.ts index 86827e1..b08efa5 100644 --- a/src/lib/worker/SceneWorkerController.ts +++ b/src/lib/worker/SceneWorkerController.ts @@ -2,6 +2,12 @@ import { WorkerResponse } from './types.js'; import { RESPONSE_STATUS } from './const.js'; class SceneWorkerController { + #initialized = false; + #initializeArgs: any[]; + #initializing: Promise; + #initializingResolve: (value?: any) => void; + #initializingReject: (reason?: any) => void; + #worker: Worker; #nextId = 0; @@ -9,24 +15,53 @@ class SceneWorkerController { constructor(createWorker: () => Worker, ...initializeArgs: any[]) { this.#worker = createWorker(); + this.#initializeArgs = initializeArgs; this.#worker.addEventListener('message', (event: MessageEvent) => { this.#handleResponse(event.data); }); + } - this.request('initialize', ...initializeArgs).catch((error) => console.error(error)); + async request(func: string, ...args: any[]): Promise { + if (!this.#initialized) { + if (this.#initializing) { + await this.#initializing; + } else { + await this.#initialize(); + } + } + + return this.#request(func, args); } - request(func: string, ...args: any[]): Promise { + #request(func: string, args: any[]): Promise { const id = this.#nextId++; - const requestPromise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { this.#pending.set(id, { resolve, reject }); }); this.#worker.postMessage({ id, func, args }); - return requestPromise; + return promise; + } + + #initialize() { + this.#initializing = new Promise((resolve, reject) => { + this.#initializingResolve = resolve; + this.#initializingReject = reject; + }); + + this.#request('initialize', this.#initializeArgs) + .then((response) => { + this.#initialized = true; + this.#initializingResolve(response); + }) + .catch((error) => { + this.#initializingReject(error); + }); + + return this.#initializing; } #handleResponse(response: WorkerResponse) {