UNPKG

workway

Version:

A general purpose, Web Worker driven, remote namespace with classes and methods.

108 lines (107 loc) 3.46 kB
function workway(file) {'use strict'; /*! (c) 2018 Andrea Giammarchi (ISC) */ return new Promise(function (res) { function uid() { return ++i + Math.random(); } var i = 0; var channel = uid(); var messages = {}; var worker = typeof file === 'string' ? new Worker(file) : file; worker.addEventListener('message', function (event) { if (event.data.channel !== channel) return; event.stopImmediatePropagation(); var namespace = event.data.namespace; if (namespace) { var Class = function (info) { var path = info.path; var methods = info.methods; var statics = info.statics; var wm = new WeakMap; function RemoteClass() { wm.set(this, uid()); } methods.forEach(function (method) { RemoteClass.prototype[method] = function () { return send({ args: slice.call(arguments), path: path, method: method, object: { id: wm.get(this), value: this } }); }; }); statics.methods.forEach(function (method) { RemoteClass[method] = function () { return send({ args: slice.call(arguments), path: path, method: method }); }; }); statics.values.forEach(function (pair) { RemoteClass[pair[0]] = pair[1]; }); return RemoteClass; }; var callback = function (path) { return function remoteCallback() { return send({ args: slice.call(arguments), path: path }); }; }; var send = function (message) { var resolve, reject; var promise = new Promise(function (res, rej) { resolve = res; reject = rej; }); promise.resolve = resolve; promise.reject = reject; messages[message.id = uid()] = promise; worker.postMessage({ channel: channel, message: message }); return promise; }; var slice = [].slice; (function update(namespace) { Object.keys(namespace).forEach(function (key) { var info = namespace[key]; switch (info.type) { case 'class': namespace[key] = Class(info); break; case 'function': namespace[key] = callback(info.path); break; case 'object': update(namespace[key] = info.value); break; default: namespace[key] = info.value; } }); }(namespace)); res({ worker: worker, namespace: namespace }); } else { var message = event.data.message; var id = message.id; var promise = messages[id]; delete messages[id]; if (message.hasOwnProperty('error')) { var error, facade = message.error; if (facade.hasOwnProperty('source')) error = facade.source; else { error = new Error(facade.message); error.stack = facade.stack; } promise.reject(error); } else promise.resolve(message.result); } }); worker.postMessage({channel: channel}); }); }