Monday, May 12, 2014

Code for Javascript Web Workers in same file as main script

Javascript's Web Workers (actually HTML 5's) have a lot of potential and they're surprisingly safe to use. They're safe because we sacrifice one of the main benefits of threading: sharing memory. Values between the main thread and worker threads are copied, not pointed to, so you have that overhead to deal with. (You send messages between threads rather than sharing memory.)

Anyway, in JS libraries especially, it can be useful to spawn worker threads, but it's inconvenient to have those functions in entirely separate files sometimes. I'm not 100% sure of the implications yet, but I had some success with the following template:

/*
Template for worker script in same file as main script;
adapted from http://stackoverflow.com/a/10136565/1048862
to make it a little cleaner
*/
(function(global)
{
  "use strict";

  var isWorker = !global.document;

if (isWorker)
WorkerThread();
else
MainThread();



// Entry point for when we're a worker thread
function WorkerThread()
{
global.onmessage = messageReceived;


// Worker thread execution goes here...
// This is how to pass messages back to the main/parent script
// global.postMessage("From worker!");
// (messages can also be objects)

function messageReceived(e)
{
console.log("Worker received message from parent:");
console.log(e.data);
}
}



// Entry point for the main thread
function MainThread()
{
var SCRIPT_PATH = getScriptPath();

// Main script execution goes here...
// This is how to start new workers and pass messages:
// var w = newWorker();
// w.postMessage("From parent!");


function getScriptPath()
{
var id = "worker" + String(Math.random()).substr(2);
document.write('<script id="'+id+'"></script>');
return document.getElementById(id).previousSibling.src;
}

function newWorker()
{
var w = new global.Worker(SCRIPT_PATH);
w.onmessage = messageReceived;
return w;
}

function messageReceived(e)
{
console.log("Parent received message from worker: ", e.data);
}
}

})(this);

Anyway, I think I might use this again.