/* * This is basically a Javascript Proxy for 'new Worker()' * which allows calling worker-functions via promises. * * It's basically comlink without the fat. * * const w = new PromiseWorker("worker.js", (cb,event_or_fn,data) => { * cb(event_or_fn,data) // decorate/ratelimit/hooks here * }) * w.foo().then( console.dir ) * * in worker.js define a function: this.foo = () => return {foo:"Bar"} */ function PromiseWorker(file, onmessage){ let proxy const worker = new Worker(file) worker.onmessage = (e) => { // handle messages originating from worker const {event,data} = e.data // this is worker.onmessage(...) const cb = (event,data) => () => { // if( data.promiseId ){ // proxy.resolver(data) // forward to promise resolver } } onmessage(cb,event,data) } return proxy = new Proxy(this,{ get(me,k){ if( k.match(/(postMessage|onmessage)/) ) return worker[k].bind(worker) if( k.match(/(resolver|promise)/) ) return this[k].bind(this) // promisify postMessage(...) call return function(){ return this.promise(me,{event: k, data: [...arguments] }) } }, promise(me,msg){ if( typeof msg != 'object' || !msg.event || !msg.data ){ throw 'worker.promise({event:..,data:..}) did not receive correct msg : '+JSON.stringify(msg) } this.resolvers = this.resolvers || {last:1,pending:{}} msg.data.promiseId = this.resolvers.last++ // Send id and task to WebWorker worker.postMessage(msg, PromiseWorker.prototype.getTransferable(msg.data) ) return new Promise( resolve => this.resolvers.pending[ msg.data.promiseId ] = resolve ); }, resolver(data){ if( !data || !data.promiseId ) throw 'promiseId not given' this.resolvers.pending[ data.promiseId ](data.result); delete this.resolvers.pending[ data.promiseId ]; // Prevent memory leak } }) } PromiseWorker.prototype.getTransferable = function(data){ let objs = [] function isTransferable(obj) { return obj instanceof ArrayBuffer || obj instanceof MessagePort || obj instanceof ImageBitmap || (typeof OffscreenCanvas !== 'undefined' && obj instanceof OffscreenCanvas) || (typeof ReadableStream !== 'undefined' && obj instanceof ReadableStream) || (typeof WritableStream !== 'undefined' && obj instanceof WritableStream) || (typeof TransformStream !== 'undefined' && obj instanceof TransformStream); } for( var i in data ){ if( isTransferable(data[i]) ) objs.push(data[i]) } if( objs.length ) debugger return objs.length ? objs : undefined }