Skip to content

Instantly share code, notes, and snippets.

@adambarry
Last active April 27, 2021 15:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adambarry/d99c1c955ce4bd2c77936d16c60dd80b to your computer and use it in GitHub Desktop.
Save adambarry/d99c1c955ce4bd2c77936d16c60dd80b to your computer and use it in GitHub Desktop.
Promise-based Web Worker (multi-threading) service for AngularJS
(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