Skip to content
Create a gist now

Instantly share code, notes, and snippets.

BuildBridgedWorker is a function that makes communication between worker and main thread simple. It also means you can keep all related code in the same file, which is convenient.
var workerCode = function(){
"use strict;" //this will become the first line of the worker
var v = a+b+c+d; //trivial calculation
var v = new Uint32Array(buff);
for(var i=0;i<v.length;i++)
v[i] /= d;
main.PlotFraction(v.buffer,"done",0,2,"world",[v.buffer]); //the buffer is fully transfered to the main thread (google "transferable objects javascript")
//the BuildBridgedWorker will add some extra code on the end to form the complete worker code
var DisplayResult = function(val,str){
// do something here
var PlotFraction = function(buffer,str1,p1,p2,str2){
// do something here
var theWorker = BuildBridgedWorker( workerCode,
["CalculateSomething","CalculateSomethingBig*"], //note asterisk indicating ArrayBuffer transfer
["DisplayResult", "PlotFraction*"],
// Some example inputs
var w=9,x=100,y=0,z=2;
var v = new Uint32Array(100);
// And this is how you call the functions in the worker...
// Note that with the CalculateSomethingBig the buffer is transfered to the worker thread (and dissapears on the main thread)
var BuildBridgedWorker = function(workerFunction,workerExportNames,mainExportNames,mainExportHandles){
//workerFunciton is a function, the interior of which will be turned into a string and used as a worker
//workerExportNames should be an array of string function names available to main
//mainExportNames should be an array of string function names available to worker
//mainExportHandles should be an array of the actual functions corresponding to the functions in main
//for both Names arrays, if the function name ends in an asterisk it means that the last argument passed is going to be an array of ArrayBuffers
//The result of all this work is that inside the worker we can call main.SomeMainFunction(thing,otherthing,more,[buffer1,buffer2])
//and in main we can call myWorker.SomeWorkerFunction(hello,world,[buffer1,buffer2])
var baseWorkerStr = workerFunction.toString().match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1];
var extraWorkerStr = [];
// build a string for the worker end of the worker-calls-funciton-in-main-thread operation
extraWorkerStr.push("var main = {};\n");
for(var i=0;i<mainExportNames.length;i++){
var name = mainExportNames[i];
if(name.charAt(name.length-1) == "*"){
name = name.substr(0,name.length-1);
mainExportNames[i] = name;//we need this trimmed version back in main
extraWorkerStr.push("main." + name + " = function(/* arguments */){\n var args =; var buffers = args.pop(); \n self.postMessage({foo:'" + name + "', args:args},buffers)\n}; \n");
extraWorkerStr.push("main." + name + " = function(/* arguments */){\n var args =; \n self.postMessage({foo:'" + name + "', args:args})\n}; \n");
// build a string for the worker end of the main-thread-calls-function-in-worker operation
var tmpStr = [];
for(var i=0;i<workerExportNames.length;i++){
var name = workerExportNames[i];
name = name.charAt(name.length-1) == "*" ? name.substr(0,name.length-1) : name;
tmpStr.push(name + ": " + name);
extraWorkerStr.push("var foos={" + tmpStr.join(",") + "};\n");
extraWorkerStr.push("self.onmessage = function(e){\n");
extraWorkerStr.push("if( in foos) \n foos[].apply(null,; \n else \n throw(new Error('Main thread requested function ' + + '. But it is not available.'));\n");
var fullWorkerStr = baseWorkerStr + "\n\n/*==== STUFF ADDED BY BuildBridgeWorker ==== */\n\n" + extraWorkerStr.join("");
// create the worker
var url = window.URL.createObjectURL(new Blob([fullWorkerStr],{type:'text/javascript'}));
var theWorker = new Worker(url);
// buid a funcion for the main part of worker-calls-function-in-main-thread operation
theWorker.onmessage = function(e){
var fooInd = mainExportNames.indexOf(;
if(fooInd != -1)
throw(new Error("Worker requested function " + + ". But it is not available."));
// build an array of functions for the main part of main-thread-calls-function-in-worker operation
var ret = {blobURL: url};//this is useful to know for debugging if you have loads of bridged workers in blobs with random names
var makePostMessageForFunction = function(name,hasBuffers){
return function(/*args...,[ArrayBuffer,..]*/){var args =; var buffers = args.pop(); theWorker.postMessage({foo:name,args:args},buffers);}
return function(/*args...*/){var args =; theWorker.postMessage({foo:name,args:args});};
for(var i=0;i<workerExportNames.length;i++){
var name = workerExportNames[i];
if(name.charAt(name.length-1) == "*"){
name = name.substr(0,name.length-1);
ret[name] = makePostMessageForFunction(name,true);
ret[name] = makePostMessageForFunction(name,false);
return ret; //we return an object which lets the main thread call the worker. The object will take care of the communication in the other direction.

I'm using this function to calculate temporal autocorrelations of neuronal activity in a webworker - see temporalcorr.js in

blittle commented Dec 31, 2013

It would be convenient if this was published on npm or bower. Mind if I do?

d1manson commented Jan 3, 2014

blittle - sure, go for it. Maybe tidy it up a bit before hand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.