From 4f3ed367fe8b1b42c470399f9b89634e64460721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Fri, 2 Feb 2024 12:56:34 +0100 Subject: [PATCH] Add service worker support --- index.js | 46 ++++++++++++++++++++++++++++++++-------------- worker.js | 18 ++++++++++++------ 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/index.js b/index.js index 7aec971..2d3e10b 100644 --- a/index.js +++ b/index.js @@ -329,15 +329,39 @@ class WorkerHelper { this._messagesByIdMap = new Map(); this._pinged = false; this._bad = false; - this._worker = this._createWorker(url, workerType); - this._worker.addEventListener('error', (e) => { + this._readyPromise = this._createWorker(url, workerType); + } + async _createWorker(url, workerType) { + const workerUrl = `${url}?${workerType}`; + if (workerType === 'dedicated') { + this._worker = new Worker(workerUrl, {type: 'module'}); + this._init(this._worker); + return Promise.resolve(); + } + if (workerType === 'shared') { + const worker = new SharedWorker(workerUrl, {type: 'module'}); + this._worker = worker.port; + this._init(this._worker); + return Promise.resolve(); + } + if (workerType === 'service') { + const registration = await navigator.serviceWorker.register(workerUrl); + await navigator.serviceWorker.ready; + this._worker = registration.active; + this._init(navigator.serviceWorker); + return Promise.resolve(); + } + return Promise.reject(`unknown worker type: ${workerType}`); + } + _init(worker) { + worker.addEventListener('error', (e) => { this._bad = true; // reject all existing promises this._promisesByIdMap.forEach(({reject}) => { reject(); }); }); - this._worker.onmessage = (e) => { + worker.onmessage = (e) => { const {id, data} = e.data; if (data == "messageerror") { this._bad = true; @@ -360,17 +384,6 @@ class WorkerHelper { } })(); } - _createWorker(url, workerType) { - const workerUrl = `${url}?${workerType}`; - if (workerType === 'dedicated') { - return new Worker(workerUrl, {type: 'module'}); - } - if (workerType === 'shared') { - const worker = new SharedWorker(workerUrl, {type: 'module'}); - return worker.port; - } - throw new Error(`unknown worker type: ${workerType}`) - } _process(id) { const p = this._promisesByIdMap.get(id); if (this._bad) { @@ -385,6 +398,9 @@ class WorkerHelper { p.resolve(data); } } + ready() { + return this._readyPromise; + } async getMessage(command, data = {}, transfer = []) { let resolve; let reject; @@ -438,6 +454,7 @@ async function checkWorkers(workerType) { let worker; try { worker = new WorkerHelper('worker.js', workerType); + await worker.ready(); } catch(error) { addElemToDocument(el('table', { className: 'worker' }, [ el('tbody', {}, setLikeToTableRows(undefined)), @@ -602,6 +619,7 @@ async function main() { await checkMisc({haveFallback}); await checkWorkers('dedicated'); await checkWorkers('shared'); + await checkWorkers('service'); // Add a copy handler to massage the text for plain text. document.addEventListener('copy', (event) => { diff --git a/worker.js b/worker.js index 378a4f0..a3f74ba 100644 --- a/worker.js +++ b/worker.js @@ -60,16 +60,17 @@ const handlers = { }; function handleMessage(e) { - const {command, id, data} = e.data; - const handler = handlers[command]; - if (!handler) { - throw new Error(`unknown command: ${command}`); + try { + const {command, id, data} = e.data; + const handler = handlers[command]; + handler.call(this, id, data); + } catch(error) { + this.postMessage({data: 'messageerror'}); } - handler.call(this, id, data); } self.onmessage = function(e) { - handleMessage.call(self, e); + handleMessage.call(e.source || self, e); }; self.onconnect = function(e) { @@ -81,3 +82,8 @@ self.onconnect = function(e) { port.postMessage({data: 'messageerror'}); }; }; + +self.onmessageerror = (e) => { + const source = e.source || self; + source.postMessage({data: 'messageerror'}); +}