Wie kann angleJS Webworker verwenden, um Prozesse im Hintergrund auszuführen? Gibt es ein Muster, dem ich dabei folgen sollte?
Derzeit verwende ich einen Dienst, der das Modell in einem separaten Web-Worker hat. Dieser Service implementiert Methoden wie:
ClientsFacade.calculateDebt(client1); //Just an example..
In der Implementierung sendet diese Methode eine Nachricht mit den Daten an den Worker. Auf diese Weise kann ich die Tatsache abstrahieren, dass es in einem separaten Thread ausgeführt wird, und ich könnte auch eine Implementierung bereitstellen, die Abfragen an einen Server oder sogar eine, die diese Aktion im selben Thread ausführt.
Da ich neu in Javascript bin und nur das Wissen wiederverwerte, das ich von anderen Plattformen habe, frage ich mich, ob Sie dies tun würden oder ob Angular, das ich verwende, eine Art Möglichkeit bietet, dies zu tun. Dies führt auch zu einer Änderung meiner Architektur, da der Worker Änderungen explizit an den Controller senden muss, der dann seine Werte aktualisiert. Dies spiegelt sich dann in der Ansicht wider. Bin ich über das Engineering hinaus? Es ist ein bisschen frustrierend, dass Web-Worker mich so sehr vor Misserfolgen "schützen", indem sie mir nicht erlauben, Speicher usw. zu teilen.
quelle
doWork
es erneut aufgerufen, bevor der Worker fertig ist, wird es nichtdefer
überschrieben? Das zweite Versprechen würde sich dann mit dem ersten Ergebnis auflösen, und das erste Versprechen würde sich niemals auflösen.Eine sehr interessante Frage! Ich finde die Web-Worker-Spezifikation etwas umständlich (wahrscheinlich aus guten Gründen, aber immer noch umständlich). Die Notwendigkeit, den Worker-Code in einer separaten Datei zu speichern, erschwert das Lesen der Absicht eines Dienstes und führt Abhängigkeiten zu statischen Datei-URLs in Ihrem eckigen Anwendungscode ein. Dieses Problem kann mithilfe der URL.createObjectUrl () behoben werden, mit der eine URL für eine JavaScript-Zeichenfolge erstellt werden kann. Auf diese Weise können wir den Worker-Code in derselben Datei angeben, in der der Worker erstellt wird.
var blobURL = URL.createObjectURL(new Blob([ "var i = 0;//web worker body" ], { type: 'application/javascript' })); var worker = new Worker(blobURL);
Die Web-Worker-Spezifikation hält auch die Worker- und Haupt-Thread-Kontexte vollständig getrennt, um Situationen zu vermeiden, in denen Deadlocks und Livelocks usw. auftreten können. Es bedeutet aber auch, dass Sie im Arbeiter keinen Zugriff auf Ihre eckigen Dienste haben, ohne etwas herumzuspielen. Dem Worker fehlen einige der Dinge, die wir (und eckig) erwarten, wenn wir JavaScript im Browser ausführen, wie die globale Variable "document" usw. Durch "Verspotten" dieser erforderlichen Browserfunktionen im Worker können wir eckig ausführen.
var window = self; self.history = {}; var document = { readyState: 'complete', cookie: '', querySelector: function () {}, createElement: function () { return { pathname: '', setAttribute: function () {} }; } };
Einige Funktionen funktionieren offensichtlich nicht, Bindungen an das DOM usw. Aber das Injection-Framework und zum Beispiel der $ http-Dienst funktionieren einwandfrei, was wir wahrscheinlich von einem Worker erwarten. Was wir dadurch gewinnen, ist, dass wir in einem Arbeiter Standard-Winkeldienste ausführen können. Wir können daher die im Worker verwendeten Dienste wie bei jeder anderen Winkelabhängigkeit einem Unit-Test unterziehen.
Ich einen Beitrag , die ein bisschen mehr über diese erarbeitet hier und ein GitHub Repo geschaffen , die einen Dienst erstellt , die implementiert die Ideen oben diskutierten hier
quelle
Ich habe hier in Angular ein voll funktionsfähiges Beispiel für Web-Worker gefunden
webworker.controller('webWorkerCtrl', ['$scope', '$q', function($scope, $q) { $scope.workerReplyUI; $scope.callWebWorker = function() { var worker = new Worker('worker.js'); var defer = $q.defer(); worker.onmessage = function(e) { defer.resolve(e.data); worker.terminate(); }; worker.postMessage("http://jsonplaceholder.typicode.com/users"); return defer.promise; } $scope.callWebWorker().then(function(workerReply) { $scope.workerReplyUI = workerReply; }); }]);
Es verwendet Versprechen, um darauf zu warten, dass der Arbeiter das Ergebnis zurückgibt.
quelle
Wenn Sie mit den Workern in AngularJS zu tun haben, muss Ihr Worker-Skript häufig inline sein (falls Sie einige Build-Tools wie gulp / grunt verwenden). Dies können wir mit dem folgenden Ansatz erreichen.
Das folgende Beispiel zeigt auch, wie mit Arbeitern Abfragen auf dem Server durchgeführt werden können:
Lassen Sie uns zuerst unsere Arbeiterfabrik erstellen:
module.factory("myWorker", function($q) { var worker = undefined; return { startWork: function(postData) { var defer = $q.defer(); if (worker) { worker.terminate(); } // function to be your worker function workerFunction() { var self = this; self.onmessage = function(event) { var timeoutPromise = undefined; var dataUrl = event.data.dataUrl; var pollingInterval = event.data.pollingInterval; if (dataUrl) { if (timeoutPromise) { setTimeout.cancel(timeoutPromise); // cancelling previous promises } console.log('Notifications - Data URL: ' + dataUrl); //get Notification count var delay = 5000; // poller 5sec delay (function pollerFunc() { timeoutPromise = setTimeout(function() { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { var response = JSON.parse(xmlhttp.responseText); self.postMessage(response.id); pollerFunc(); } }; xmlhttp.open('GET', dataUrl, true); xmlhttp.send(); }, delay); })(); } } } // end worker function var dataObj = '(' + workerFunction + ')();'; // here is the trick to convert the above fucntion to string var blob = new Blob([dataObj.replace('"use strict";', '')]); // firefox adds user strict to any function which was blocking might block worker execution so knock it off var blobURL = (window.URL ? URL : webkitURL).createObjectURL(blob, { type: 'application/javascript; charset=utf-8' }); worker = new Worker(blobURL); worker.onmessage = function(e) { console.log('Worker said: ', e.data); defer.notify(e.data); }; worker.postMessage(postData); // Send data to our worker. return defer.promise; }, stopWork: function() { if (worker) { worker.terminate(); } } } });
Rufen Sie als nächstes von unserer Steuerung aus die Arbeiterfabrik an:
var inputToWorker = { dataUrl: "http://jsonplaceholder.typicode.com/posts/1", // url to poll pollingInterval: 5 // interval }; myWorker.startWork(inputToWorker).then(function(response) { // complete }, function(error) { // error }, function(response) { // notify (here you receive intermittent responses from worker) console.log("Notification worker RESPONSE: " + response); });
Sie können
myWorker.stopWork();
jederzeit anrufen, um den Worker von Ihrem Controller aus zu beenden!Dies wird in IE11 + und FF und Chrome getestet
quelle
Sie können sich auch das Winkel-Plugin https://github.com/vkiryukhin/ng-vkthread ansehen
Hiermit können Sie eine Funktion in einem separaten Thread ausführen. Grundverwendung:
/* function to execute in a thread */ function foo(n, m){ return n + m; } /* create an object, which you pass to vkThread as an argument*/ var param = { fn: foo // <-- function to execute args: [1, 2] // <-- arguments for this function }; /* run thread */ vkThread.exec(param).then( function (data) { console.log(data); // <-- thread returns 3 } );
Beispiele und API-Dokument: http://www.eslinstructor.net/ng-vkthread/demo/
- Vadim
quelle