Der Browser dient schon lange nicht mehr nur als einfaches Anzeigeinstrument für Webseiten. JavaScript übernimmt mehr und mehr Aufgaben die früher auf dem Server abgewickelt werden mussten, dank performanter Endgeräte aber zunehmend auch im Browser behandelt werden. Nun ist es aber so das JavaScript single-threaded ist und CPU-intensive Funktionalitäten zum einfrieren der GUI führen. Abhilfe? WebWorker!
WebWorker ermöglichen es uns parallelen Code aus zu führen, also abseits des Threads der sich um die Abwicklung der GUI Interaktion kümmert. Technische Vorraussetzung dafür ist das der Code des WebWorkers in einer separaten Datei abgelegt wird und mittels asyncronen Event-Handling mit der Anwendung kommuniziert. Insbesonderer der erste Teil hat es vor der Angular Version 8 schwierig gemacht mit diesen zu arbeiten, sorgt Angular durch seinen Buildprozess für das Zusammenführen aller Dateien. Seit Angular 8 unterstützt die Angular-CLI aber die Generierung für WebWorker:
ng generate web-worker [name]
Neben der Erstellung einer entsprechenden Worker-Datei bereitet Angular unsere Anwendung auch für diese vor. So wird neben einer Anpassung an der CLI( angular.json ) auch die TypeScript-Konfiguation angepasst um das spätere Zusammenführen der Dateien zu umgehen. Ein WebWorker besteht dann aus einer einfachen Funktion die Parameter entgegen nimmt und und über eine ensprechende Funktion eine Rückgabe liefern kann:
addEventListener('message', ({ data }) => {
for (let i = 0; i < data.times; i++) {
data.result = data.result * data.multiplier;
}
postMessage(data.result);
});
Die Verwendung dieser Funktion ähnelt dann ein wenig der Verwendung von asycronen Service-Methoden, mit dem Unterscheid das wir im Vorfeld explizit ein WebWorker Objekt erzeugen:
calculateWW() {
const worker = new Worker('./multiplier.worker.ts', { type: 'module' });
worker.onmessage = ({ data }) => {
this.form.get('result').setValue(data);
};
this.form.get('result').setValue(this.form.get('initValue').value);
worker.postMessage(this.form.value);
}
So registrieren wir einen EventListener der benachrichtigt wird wenn der Worker eine Rückgabe liefert ( Zeile 4 ) und rufen den Worker mit frei wählbaren Parametern auf( Zeile 8 )