Last active
October 5, 2024 19:51
-
-
Save BananaAcid/b8e3d609c5655301eccaeb44c9df9037 to your computer and use it in GitHub Desktop.
create an in-memory worker by passing a function or promise and be able to await its return-result, args must be serializable
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* create an in-memory worker by passing a function or promise and be able to await its return-result, args must be serializable | |
* | |
* @author Nabil Redmann | |
* @license MIT | |
* | |
* @see https://gist.github.com/BananaAcid/b8e3d609c5655301eccaeb44c9df9037 | |
* @reference https://stackoverflow.com/a/19201292/1644202 | |
*/ | |
// fn can be function or async | |
// args are the params for the fn | |
// bound contexts are ignored (.toString() will not contain .bind() contexts) | |
// the worker always posts back if done! if something is returned from a the provided fn, it will be returned from callFnInThread(). | |
// | |
// need other files or functions in the worker? just convert them to string (`.toString()`) and add them to the beginning of the blob as array values -- max size: https://stackoverflow.com/a/43816041/1644202 | |
// or: your browser is updated to a current version, it will support module workers; {type: 'module'} and imports ... see: https://stackoverflow.com/a/45578811/1644202 | |
// put the import statements as string to the blob array, preceeding the promise, or use `import(...)` | |
async function callFnInThread(fn, ...args) { | |
return await new Promise((resolve, reject) => { | |
let blobUrl = URL.createObjectURL( new Blob([`Promise.resolve( ${fn.toString()}.apply(self, ${JSON.stringify(args)}) ).then(r => self.postMessage(r))`]), {type: 'application/javascript'}); | |
let worker = new Worker( blobUrl ); | |
worker.onmessage = ev => { | |
URL.revokeObjectURL(blobUrl); | |
resolve(ev.data); | |
} | |
worker.onerror = err => { | |
URL.revokeObjectURL(blobUrl); | |
reject(err); | |
} | |
}); | |
} | |
// some test fns | |
function test1() { | |
return 'done'; | |
} | |
async function test2() { | |
await new Promise(r => setTimeout(r, 1000)); | |
return 'done'; | |
} | |
function test3(a) { | |
return 'done: ' + a; | |
} | |
async function test4(a, b) { | |
await new Promise(r => setTimeout(r, 1000)); | |
return 'done: ' + a + ' --- ' + b; | |
} | |
function error1(a) { | |
return 'done: ' + a; | |
} | |
function error2() { | |
// do not return anything, works as well | |
} | |
function error3() { | |
throw new Error('Dang!'); | |
} | |
// Tests | |
let result = await callFnInThread(test1); | |
console.log('RESULT', result); | |
let result2 = await callFnInThread(test2); | |
console.log('RESULT', result2); | |
let result3 = await callFnInThread(test3, 123); | |
console.log('RESULT', result3); | |
let result4 = await callFnInThread(test4, 123, 456); | |
console.log('RESULT', result4); | |
let resultErr1 = await callFnInThread(error1); | |
console.log('RESULT', resultErr1); // done: undefined | |
let resultErr2 = await callFnInThread(error2); | |
console.log('RESULT', resultErr2); // undefined | |
let resultErr3 = await callFnInThread(error3); | |
console.log('RESULT', resultErr3); // triggers uncought error, no console.log is not reached | |
let resultErr3_2 = await callFnInThread(error3).catch(e => null); | |
console.log('RESULT', resultErr3_2); // null ---> cought, but show the original uncought error from the web worker in the console | |
// ---------------------------------------------------------------------------------------- | |
// would not be able to receive result! Is just for fireing them off | |
let fn = test1; | |
navigator.serviceWorker.controller.postMessage([ | |
'dyn_workers/' + (fn.prototype.name || 'fn' + Date.now()) + '.js', | |
`Promise.resolve(${fn.toString()})` // resolves functions and asyncs | |
]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment