Reintroducing WebWorkers (pfeeew, Vite makes it tough !)

This commit is contained in:
vdv committed 2022-11-26 19:36:55 +01:00
1 parent 02f02984e5
commit 5de30283b1
52 files changed
+3362 -47

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
import dispatch, { init, worker } from './dispatcher-main';
jest.mock('./get-worker', () => ({
getWorker: () => ({
port: {
postMessage: jest.fn(),
},
}),
}));
describe('The dispatcher-main', () => {
beforeEach(() => {
init();
});
test('should create a new shared web worker', () => {
expect(worker).toBeDefined();
});
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 forward the message', () => {
dispatch('ping');
expect(worker.port.postMessage).toBeCalledWith({ id: 0, payload: 'ping' });
});
test('should return the response', () => {
var response;
const callback = (error, success) => {
response = success;
};
dispatch('ping', callback);
worker.port.onmessage({ data: { id: 0, payload: 'pong' } });
expect(response).toEqual('pong');
});
});
+53
View File
@@ -0,0 +1,53 @@
import { getWorker } from './get-worker';
declare global {
var dispatcherQueue: { index: number; queue: Map<number, any> };
}
export var worker: any;
export const init = () => {
console.log({ caller: 'dispatcher-main / init' });
globalThis.dispatcherQueue = { index: 0, queue: new Map() };
console.log({ caller: 'dispatcher-main / init', globalThis });
worker = getWorker();
console.log({ caller: 'dispatcher-main / init', worker });
worker.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.postMessage(message);
console.log({ caller: 'dispatcher-main / dispatch', message });
};
export default dispatch;
+33
View File
@@ -0,0 +1,33 @@
import worker from './dispatcher-worker';
jest.mock('../db', () => ({
initDb: () => 'called initDb',
}));
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 back an unknownAction', async () => {
await port.onmessage({ data: { id: 5, payload: { action: 'ping' } } });
expect(port.postMessage).toBeCalledWith({
id: 5,
payload: 'unknownAction',
});
});
test('calls initDb when required', async () => {
await port.onmessage({ data: { id: 5, payload: { action: 'initDb' } } });
expect(port.postMessage).toBeCalledWith({
id: 5,
payload: 'called initDb',
});
});
});
+42
View File
@@ -0,0 +1,42 @@
/// <reference lib="webworker" />
import { initDb } from '../db';
import {
putNewGpx,
existsGpx,
pruneAndSaveImportedGpx,
getGpxesForViewport,
getGpx,
} from '../db/gpx';
import { getTrk, putNewTrk } from '../db/trk';
import { getTrkseg } from '../db/trkseg';
const self = globalThis as unknown as WorkerGlobalScope;
const actions = {
initDb,
putNewGpx,
putNewTrk,
existsGpx,
pruneAndSaveImportedGpx,
getGpxesForViewport,
getGpx,
getTrk,
getTrkseg,
};
console.log({ caller: 'dispatcher-worker', actions });
onmessage = async function (e) {
console.log({ caller: 'dispatcher-worker / onmessage', e });
const { id, payload } = e.data;
console.log(`payload.action in actions: ${payload.action in actions}`);
var returnValue: any = 'unknownAction';
if (payload.action in actions) {
returnValue = await actions[<keyof typeof actions>payload.action](
payload.params
);
}
postMessage({ id: id, payload: returnValue });
};
//export default self;
+8
View File
@@ -0,0 +1,8 @@
export const getWorker = () => {
console.log({ caller: 'getWorker' });
return new Worker(new URL('./dispatcher-worker', import.meta.url), {
type: 'module',
});
};
export default getWorker;