Angular 8 - Web Workers


Advertisements

Web workers enables JavaScript application to run the CPU-intensive in the background so that the application main thread concentrate on the smooth operation of UI. Angular provides support for including Web workers in the application. Let us write a simple Angular application and try to use web workers.

Create a new Angular application using below command −

cd /go/to/workspace
ng new web-worker-sample

Run the application using below command −

cd web-worker-sample
npm run start

Add new web worker using below command −

ng generate web-worker app

The output of the above command is as follows −

CREATE tsconfig.worker.json (212 bytes)
CREATE src/app/app.worker.ts (157 bytes)
UPDATE tsconfig.app.json (296 bytes)
UPDATE angular.json (3776 bytes)
UPDATE src/app/app.component.ts (605 bytes)

Here,

  • app refers the location of the web worker to be created.
  • Angular CLI will generate two new files, tsconfig.worker.json and src/app/app.worker.ts and update three files, tsconfig.app.json, angular.json and src/app/app.component.ts file.

Let us check the changes −

// tsconfig.worker.json
{
   "extends": "./tsconfig.json",
   "compilerOptions": {
      "outDir": "./out-tsc/worker",
      "lib": [
         "es2018",
         "webworker"
      ],


      "types": []
   },
   "include": [
      "src/**/*.worker.ts"
   ]
}

Here,

tsconfig.worker.json extends tsconfig.json and includes options to compile web workers.

// tsconfig.app.json [only a snippet]
"exclude": [
   "src/test.ts",
   "src/**/*.spec.ts",
   "src/**/*.worker.ts"
]

Here,

Basically, it excludes all the worker from compiling as it has separate configuration.

// angular.json (only a snippet) "webWorkerTsConfig": "tsconfig.worker.json"

Here,

angular.json includes the web worker configuration file, tsconfig.worker.json.

// src/app/app.worker.ts
addEventListener('message', ({ data }) => {
   const response = `worker response to ${data}`;
   postMessage(response);
});

Here,

A web worker is created. Web worker is basically a function, which will be called when a message event is fired. The web worker will receive the data send by the caller, process it and then send the response back to the caller.

// src/app/app.component.ts [only a snippet]
if (typeof Worker !== 'undefined') {
   // Create a new
   const worker = new Worker('./app.worker', { type: 'module' });
   worker.onmessage = ({ data }) => {
      console.log(`page got message: ${data}`);
   };
   worker.postMessage('hello');
} else {

   // Web Workers are not supported in this environment.
   // You should add a fallback so that your program still executes correctly.
}

Here,

  • AppComponent create a new worker instance, create a callback function to receive the response and then post the message to the worker.

Restart the application. Since the angular.json file is changed, which is not watched by Angular runner, it is necessary to restart the application. Otherwise, Angular does not identify the new web worker and does not compile it.

Let us create Typescript class, src/app/app.prime.ts to find nth prime numbers.

export class PrimeCalculator
{
   static isPrimeNumber(num : number) : boolean {
      if(num == 1) return true;

      let idx : number = 2;
      for(idx = 2; idx < num / 2; idx++)
      {
         if(num % idx == 0)
            return false;
      }

      return true;
   }

   static findNthPrimeNumber(num : number) : number {
      let idx : number = 1;
      let count = 0;

      while(count < num) {
         if(this.isPrimeNumber(idx))
            count++;

         idx++;
         console.log(idx);
      }

      return idx - 1;
   }
}

Here,

  • isPrimeNumber check whether the given number is prime or not.
  • findNthPrimeNumber finds the nth prime number.

Import the new created prime number class into src/app/app.worker.ts and change the logic of the web worker to find nth prime number.

/// <reference lib="webworker" />

import { PrimeCalculator } from './app.prime';

addEventListener('message', ({ data }) => {
   // const response = `worker response to ${data}`;
   const response = PrimeCalculator.findNthPrimeNumber(parseInt(data));
   postMessage(response);
});

Change AppComponent and include two function, find10thPrimeNumber and find10000thPrimeNumber.

import { Component } from '@angular/core';
import { PrimeCalculator } from './app.prime';

@Component({
   selector: 'app-root',
   templateUrl: './app.component.html',
   styleUrls: ['./app.component.css']
})
export class AppComponent {
   title = 'Web worker sample';
   prime10 : number = 0;
   prime10000 : number = 0;

   find10thPrimeNumber() {
      this.prime10 = PrimeCalculator.findNthPrimeNumber(10);
   }

   find10000thPrimeNumber() {
      if (typeof Worker !== 'undefined') {
         // Create a new
         const worker = new Worker('./app.worker', { type: 'module' });
         worker.onmessage = ({ data }) => {
         this.prime10000 = data;
         };
         worker.postMessage(10000);
      } else {
         // Web Workers are not supported in this environment.
         // You should add a fallback so that your program still executes correctly.
      }
   }
}

Here,

find10thPrimeNumber is directly using the PrimeCalculator. But, find10000thPrimeNumber is delegating the calculation to web worker, which in turn uses PrimeCalculator.

Change the AppComponent template, src/app/app.commands.html and include two option, one to find 10th prime number and another to find the 10000th prime number.

<h1>{{ title }}</h1>

<div>
   <a href="#" (click)="find10thPrimeNumber()">Click here</a> to find 10th prime number
   <div>The 10<sup>th</sup> prime number is {{ prime10 }}</div> <br/>
   <a href="#" (click)="find10000thPrimeNumber()">Click here</a> to find 10000th prime number
   <div>The 10000<sup>th</sup> prime number is {{ prime10000 }}</div>
</div>

Here,

Finding 10000th prime number will take few seconds, but it will not affect other process as it is uses web workers. Just try to find the 10000th prime number first and then, the 10th prime number.

Since, the web worker is calculating 10000th prime number, the UI does not freeze. We can check 10th prime number in the meantime. If we have not used web worker, we could not do anything in the browser as it is actively processing the 10000th prime number.

The result of the application is as follows −

Initial state of the application.

Workers

Click and try to find the 10000th prime number and then try to find the 10th prime number. The application finds the 10th prime number quite fast and shows it. The application is still processing in the background to find the 10000th prime number.

Web worker

Both processes are completed.

Web workers

Web worker enhances the user experience of web application by doing the complex operation in the background and it is quite easy to do it in Angular Application as well.

Advertisements