Last active
March 15, 2020 15:39
-
-
Save dtipson/d11f8068ae3a5f1907228fc2888b3705 to your computer and use it in GitHub Desktop.
Template literals allow us to write string code suitable for workers. We can even import actual functions using toString. Blob urls allow us to turn all that content into a script for the worker to run, allowing us to create and run one with no external dependencies!
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
//actual function (must be a named function declaration for use w/ toString here) | |
function addOne(x){ return x+1 }; | |
//the actual worker code can be written as a string | |
//template literals make that convienient because they support multiline | |
//note that the addOne function above can be used in this worker code, since we'll be importing it | |
const workerScript = ` | |
self.addEventListener('message', function(e) { | |
var data = e.data; | |
console.log('worker recieved: ',data); | |
self.postMessage('worker added! :'+ addOne(data.value)); | |
}, false); | |
`; | |
//main function for creating an inline worker: | |
//inlineWorker:: Array -> String -> a -> Promise b | |
const inlineWorker = (dependencies=[], scriptString, msg) => { | |
scriptString = dependencies.reduce((acc,item) => acc+item.toString(),'') + scriptString; | |
//promisify the response/error for make things easier to consume | |
const promise = new Promise( (resolve, reject) => { | |
var blob = new Blob([scriptString], { type: "text/javascript" }); | |
var bloblurl = window.URL.createObjectURL(blob); | |
var worker = new Worker(bloblurl); | |
worker.onmessage = e => { | |
resolve(e.data); | |
window.URL.revokeObjectURL(bloblurl);//remember to free up the blob url as well | |
worker.terminate(); | |
}; | |
worker.onerror = e => { | |
reject(e); | |
worker.terminate(); | |
}; | |
worker.postMessage(msg); | |
}); | |
return promise; | |
} | |
inlineWorker([addOne],workerScript,{msg:'hi', value:6}).then(x=>console.log('msg returned: ',x)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The main problem with this approach is just that linters aren't going to pick up on any errors in the template literal string (because it's just a string). So you'd either want to write/test that code before adding const stringName=``; around it, or try to define an arrow function expression with the worker code inside it and then run .toString on that (because the expression version will sort of "remove" the outer wrapping when toStrung).
There are potentially more powerful techniques possible using serviceWorkers and sharedWorkers: http://stackoverflow.com/a/19201292/1971194