Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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!
//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));
@dtipson
Copy link
Author

dtipson commented May 6, 2016

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment