UNPKG

proxied-worker

Version:

A tiny utility to asynchronously drive a namespace exposed through a Shared/Service/Worker

100 lines (83 loc) 2.23 kB
/*! (c) Andrea Giammarchi - ISC */ const APPLY = 'apply'; const GET = 'get'; const NEW = 'new'; let uid = 0; /** * Exports a namespace object with methods, properties, or classes. * @param {object} Namespace the exported namespace. */ globalThis.ProxiedWorker = function ProxiedWorker(Namespace) { const instances = new WeakMap; addEventListener('connect', ({ports = []}) => { for (const port of ports) { port.addEventListener('message', message.bind(port)); port.start(); } }); addEventListener('message', message.bind(globalThis)); async function loopThrough(_, $, list) { const action = list.shift(); let {length} = list; if (action !== GET) length--; if (action === APPLY) length--; for (let i = 0; i < length; i++) $ = await $[list[i]]; if (action === NEW) { const instance = new $(...list.pop().map(args, _)); instances.get(this).set($ = String(uid++), instance); } else if (action === APPLY) { $ = await $[list[length]](...list.pop().map(args, _)); } return $; } async function message(event) { const {source, data: {id, list}} = event; if (!/^proxied-worker:([^:]*?):-?\d+$/.test(id)) return; const instance = RegExp.$1; const bus = source || this; if (!instances.has(this)) instances.set(this, new Map); let result, error; if (instance.length) { const ref = instances.get(this); if (list.length) { try { result = await loopThrough.call(this, bus, ref.get(instance), list); } catch ({message}) { error = message; } } else { ref.delete(instance); return; } } else { try { result = await loopThrough.call(this, bus, Namespace, list); } catch ({message}) { error = message; } } bus.postMessage({id, result, error}); } }; const cbs = new Map; function args(id) { if (typeof id === 'string') { if (/^proxied-worker:cb:/.test(id)) { if (!cbs.has(id)) cbs.set(id, (...args) => { this.postMessage({id, args}); }); return cbs.get(id); } return id.slice(1); } return id; }