UNPKG

worktank

Version:

A simple isomorphic library for executing functions inside WebWorkers or Node Threads pools.

109 lines (108 loc) 3.52 kB
/* IMPORT */ import WorkerError from './error.js'; import WorkerFrontend from './frontend.js'; /* MAIN */ class Worker { /* CONSTRUCTOR */ constructor(name, bootloader) { /* EVENTS API */ this.onClose = (code) => { if (this.terminated) return; this.terminated = true; this.worker.terminate(); this.reject(new WorkerError(this.name, `Exited with exit code ${code}`)); }; this.onError = (error) => { if (this.terminated) return; this.terminated = true; this.worker.terminate(); this.reject(error); }; this.onMessage = (message) => { if (this.terminated) return; if (message.type === 'log') { this.onMessageLog(message); } else if (message.type === 'ready') { this.onMessageReady(message); } else if (message.type === 'result') { this.onMessageResult(message); } }; this.onMessageLog = (message) => { console.log(message.value); }; this.onMessageReady = (message) => { this.ready = true; this.tick(); }; this.onMessageResult = (message) => { if ('value' in message) { // Success this.resolve(message.value); } else { // Error const error = Object.assign(new Error(), message.error); this.reject(error); } }; /* API */ this.exec = (task) => { if (this.terminated) throw new WorkerError(this.name, 'Terminated'); if (this.task || this.busy) throw new WorkerError(this.name, 'Busy'); this.task = task; this.tick(); }; this.reject = (error) => { const { task } = this; if (!task) return; this.busy = false; this.task = undefined; this.timestamp = Date.now(); task.reject(error); }; this.resolve = (value) => { const { task } = this; if (!task) return; this.busy = false; this.task = undefined; this.timestamp = Date.now(); task.resolve(value); }; this.terminate = () => { if (this.terminated) return; this.terminated = true; this.worker.terminate(); this.reject(new WorkerError(this.name, 'Terminated')); }; this.tick = () => { if (this.terminated || !this.ready || !this.task || this.busy) return; this.busy = true; try { const { method, args, transfer } = this.task; this.worker.send({ type: 'exec', method, args }, transfer); } catch { this.reject(new WorkerError(this.name, 'Failed to send message')); } }; this.busy = false; this.ready = false; this.terminated = false; this.timestamp = Date.now(); this.name = name; this.bootloader = bootloader; this.worker = new WorkerFrontend(this.name, this.bootloader, this.onClose, this.onError, this.onMessage); } } /* EXPORT */ export default Worker;