78 lines
2.7 KiB
JavaScript
78 lines
2.7 KiB
JavaScript
|
/*
|
||
|
* 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
|
||
|
}
|