Last active
April 27, 2021 15:40
-
-
Save adambarry/d99c1c955ce4bd2c77936d16c60dd80b to your computer and use it in GitHub Desktop.
Promise-based Web Worker (multi-threading) service for AngularJS
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 () { | |
"use strict"; | |
/* | |
* In JavaScript, everything runs in the "main" (or "UI") thread by default, which means that if JavaScript | |
* is doing heavy calculations, e.g. crunching huge data-sets, then the UI is blocked, making e.g. scrolling, | |
* hover-effects etc. janky or down-right impossible. In order to alleviate this problem, this service | |
* enables you to create threads which run a predefined block of code after which they terminate (think of | |
* them as "Mr. Meeseeks" (from the cartoon, "Rick and Morty") for browsers: They live to serve a | |
* singular purpose after which they die. | |
* | |
* EXAMPLE (from Angular Controller) | |
//Include the Thread service as a dependency | |
Thread(function (event) { | |
//This function gets executed in its own browser-thread | |
console.group("Worker-thread"); | |
//console.log("event", event); | |
console.log("data", event.data); | |
console.groupEnd(); | |
//Return the result to the UI-thread | |
postMessage("This is a message from the worker", {}); //This is the "return" | |
}, "This value is passed to the function as event.data").then(function (res) { | |
//The worker has fulfilled its purpose | |
console.log("Thread result:", res); | |
}); | |
*/ | |
var serviceId = "Thread"; | |
angular.module("App") | |
.factory(serviceId, ["$q", | |
function ($q) { | |
/****************************************************************************** | |
* Private functions | |
******************************************************************************/ | |
function createWorker(func, data) { | |
//console.group(serviceId, "createWorker"); | |
//console.log({ | |
// func: func, | |
// data: data | |
//}); | |
var deferred = $q.defer(), | |
blob, | |
worker; | |
//Wrap the function in the "onmessage" listener to execute | |
func = "onmessage = " + func.toString(); | |
//Create a new BLOB from on the received function | |
blob = new Blob([func], { | |
type: "text/javascript" | |
}); | |
//Create the new worker (and reference it as "worker" in the UI-thread) | |
worker = new Worker(window.URL.createObjectURL(blob)); // Note: window.webkitURL.createObjectURL() in Chrome 10+. | |
worker.onmessage = function (event) { | |
//console.group("UI-thread"); | |
//console.log("event", event); | |
/* | |
* This function is triggered when the worker executes its | |
* "postMessage" function, which should be done when it has | |
* completed its purpose | |
*/ | |
var data = event.data; | |
//console.log("Data received from the worker", { | |
// data: data | |
//}); | |
//Resolve the promise | |
deferred.resolve(data); | |
/* | |
* Terminate the worker once it has completed its work. | |
* If you don't terminate the worker, you can see each new worker | |
* by going to "developer tools > sources" in Google Chrome, and I'm | |
* thinking that its better to clean them up right away | |
*/ | |
worker.terminate(); | |
//console.groupEnd(); | |
//console.groupEnd(); | |
} | |
//Trigger the onmessage-function in the worker | |
worker.postMessage(data); | |
//Return the promise | |
return deferred.promise; | |
} | |
/****************************************************************************** | |
* Public interface | |
******************************************************************************/ | |
return function (func, data) { | |
//Test if Web Workers are supported | |
if (!window.Worker) { | |
console.warn("Your browser doesn't support Web Workers"); | |
return false; | |
} | |
var deferred = $q.defer(); | |
createWorker(func, data).then(function (res) { | |
//Resolve the promise | |
deferred.resolve(res); | |
}); | |
//Return the promise | |
return deferred.promise; | |
} | |
}]); | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment