Last active
October 19, 2015 13:52
-
-
Save oakfang/34a46f402f11987f1da7 to your computer and use it in GitHub Desktop.
WebWorker module
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
function functionToBlob(func) { | |
return new Blob([`(${func.toString()})()`]); | |
} | |
function importAsBlob(func) { | |
return new Blob([`var ${func.name} = ${func.toString()}`]); | |
} | |
function getFunctionUrl(func, imported) { | |
return URL.createObjectURL((imported ? importAsBlob : functionToBlob)(func)); | |
} | |
function workerMain() { | |
this.onmessage = ({data}) => { | |
switch(data.type) { | |
case 'import': | |
importScripts(data.url); | |
this.postMessage({type: 'imported'}); | |
break; | |
case 'execute': | |
var func = this[data.function]; | |
var args = data.args; | |
try { | |
self.postMessage({ | |
type: 'return', | |
value: func(...args) | |
}); | |
} catch (err) { | |
self.postMessage({ | |
type: 'error', | |
value: err.toString() | |
}); | |
} | |
break; | |
} | |
}; | |
} | |
function createWorker() { | |
var url = getFunctionUrl(workerMain); | |
return new Worker(url); | |
} | |
function thread(func, performanceChecker) { | |
if (!func.name) { | |
throw new Error('A thread has to have a name'); | |
} | |
var executionResolver, | |
executionRejecter, | |
importResolver; | |
var worker = createWorker(); | |
var importPromise = new Promise(resolver => { | |
importResolver = resolver; | |
}); | |
worker.postMessage({ | |
type: 'import', | |
url: getFunctionUrl(func, true) | |
}); | |
worker.onmessage = function (e) { | |
switch(e.data.type) { | |
case 'error': | |
executionRejecter(e.data.value); | |
break; | |
case 'return': | |
executionResolver(e.data.value); | |
break; | |
case 'imported': | |
importResolver(); | |
} | |
}; | |
var thunk = function () { | |
var args = Array.from(arguments); | |
if (performanceChecker && !performanceChecker(...args)) { | |
console.log('Thread is too heavy for this... Using AsyncWrapper'); | |
return getAsyncWrapper(func)(...args); | |
} | |
return importPromise.then(function () { | |
worker.postMessage({ | |
type: 'execute', | |
function: func.name, | |
args: args | |
}); | |
return new Promise((resolve, reject) => { | |
executionRejecter = reject; | |
executionResolver = resolve; | |
}); | |
}); | |
}; | |
thunk.close = function () { | |
worker.terminate(); | |
}; | |
return thunk; | |
} | |
function getAsyncWrapper(func) { | |
var wrapper = function () { | |
var args = Array.from(arguments); | |
return new Promise((resolve, reject) => { | |
try { | |
resolve(func(...args)); | |
} catch (err) { | |
reject(err); | |
} | |
}) | |
}; | |
wrapper.close = function () {}; | |
return wrapper; | |
} | |
/** | |
@param {performanceChecker} if defined and resolves to false when passed the thunks arguments, will not start a new thread | |
*/ | |
export default function (func, performanceChecker) { | |
if (window.Worker && window.URL && window.Blob) { | |
return thread(func, performanceChecker); | |
} else { | |
return getAsyncWrapper(func); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment