From 9089b08c6e8efa49851f9d3d17fb225a09cde5d4 Mon Sep 17 00:00:00 2001 From: evlist Date: Sun, 6 Nov 2022 17:53:01 +0100 Subject: [PATCH] Starting to work with web workers. --- src/workers/dispatcher-main.test.js | 28 ++++++++++++++++ src/workers/dispatcher-main.ts | 47 +++++++++++++++++++++++++++ src/workers/dispatcher-worker.test.js | 19 +++++++++++ src/workers/dispatcher-worker.ts | 13 ++++++++ 4 files changed, 107 insertions(+) create mode 100644 src/workers/dispatcher-main.test.js create mode 100644 src/workers/dispatcher-main.ts create mode 100644 src/workers/dispatcher-worker.test.js create mode 100644 src/workers/dispatcher-worker.ts diff --git a/src/workers/dispatcher-main.test.js b/src/workers/dispatcher-main.test.js new file mode 100644 index 0000000..f80a883 --- /dev/null +++ b/src/workers/dispatcher-main.test.js @@ -0,0 +1,28 @@ +import dispatch, { init, worker } from './dispatcher-main'; + +describe('The dispatcher-main', () => { + var postMessage = jest.fn(); + beforeEach(() => { + global.SharedWorker = jest.fn(function (source) { + this.source = source; + this.port = { + postMessage, + }; + return this; + }); + init(); + }); + test('should create a new shared web worker', () => { + expect(SharedWorker).toBeCalled(); + }); + test('should create a onmessage function', () => { + expect(worker.port.onmessage).toBeDefined(); + }); + test('should return a promise if no callback is provided', () => { + expect(dispatch('ping')).toBeInstanceOf(Promise); + }); + test('should send back the message', () => { + dispatch('ping'); + expect(postMessage).toBeCalledWith({ id: 0, payload: 'ping' }); + }); +}); diff --git a/src/workers/dispatcher-main.ts b/src/workers/dispatcher-main.ts new file mode 100644 index 0000000..db0a7a3 --- /dev/null +++ b/src/workers/dispatcher-main.ts @@ -0,0 +1,47 @@ +declare global { + var dispatcherQueue: { index: number; queue: Map }; +} + +export var worker: any; + +export const init = () => { + globalThis.dispatcherQueue = { index: 0, queue: new Map() }; + + worker = new SharedWorker('./dispatcher-worker'); + + worker.port.onmessage = (event: any) => { + const { id, payload } = event.data; + dispatcherQueue.queue.get(id)(null, payload); + dispatcherQueue.queue.delete(id); + }; +}; + +const dispatch = ( + payload: any, + callBack?: (error: any, result: any) => void +) => { + if (worker === undefined) { + init(); + } + if (callBack === undefined) { + /** If a callback function is not provided, return a promise */ + return new Promise((resolve, reject) => { + dispatch(payload, (error, result) => { + if (error) { + reject(error); + } else { + resolve(result); + } + }); + }); + } + /** Otherwise, use the callback function */ + dispatcherQueue.queue.set(dispatcherQueue.index, callBack); + const message = { + id: dispatcherQueue.index++, + payload: payload, + }; + worker.port.postMessage(message); +}; + +export default dispatch; diff --git a/src/workers/dispatcher-worker.test.js b/src/workers/dispatcher-worker.test.js new file mode 100644 index 0000000..8e35a5f --- /dev/null +++ b/src/workers/dispatcher-worker.test.js @@ -0,0 +1,19 @@ +import worker from './dispatcher-worker'; + +describe('The dispatcher-worker ', () => { + let port; + beforeEach(() => { + port = { + postMessage: jest.fn(), + }; + worker.onconnect({ ports: [port] }); + }); + test('creates a onmessage function', () => { + expect(port.onmessage).toBeDefined(); + expect(port.postMessage).not.toBeCalled(); + }); + test('receives a ping and sends a pong', () => { + port.onmessage({ data: { id: 5, payload: 'ping' } }); + expect(port.postMessage).toBeCalledWith({ id: 5, payload: '"ping" pong' }); + }); +}); diff --git a/src/workers/dispatcher-worker.ts b/src/workers/dispatcher-worker.ts new file mode 100644 index 0000000..4660867 --- /dev/null +++ b/src/workers/dispatcher-worker.ts @@ -0,0 +1,13 @@ +const self = globalThis as unknown as SharedWorkerGlobalScope; + +self.onconnect = function (e) { + var port = e.ports[0]; + + port.onmessage = function (e) { + console.log(`Worker received ${JSON.stringify(e)}`); + const { id, payload } = e.data; + port.postMessage({ id: id, payload: `${JSON.stringify(payload)} pong` }); + }; +}; + +export default self;