DEV Community

loading...
Cover image for Supercharge your Angular application using Web Workers

Supercharge your Angular application using Web Workers

ng-conf
Home to the largest gathering of Angular developers world wide!
・4 min read

Zama Khan Mohammed | ng-conf | May 2019

UI blocking is a thing of the past!
Picture of a whirling rollercoaster. The picture is slightly overlaid with the text "Supercharge Your Angular Apps Using Web Workers".

Original 📷 by @ja5on

Add for angular. The image reads "Learn Angular Through Projects - Best way to learn any technology is by working on some Real World Projects!" There is a black button that reads "Get your copy!" in white text. Underneath is a white arrow pointing down.

https://angularprojects.com

If you are building an application where you do a lot of calculations on UI, such as creating CAD documents, doing heavy geometrical calculations, or heavy data table manipulations, then you might have observed that the UI sometimes becomes laggy or janky.

This happens because JavaScript is not the only thing that runs on the main thread, but other things like the painting of pixels, style calculations, and many others also run on it. When we run heavy long-running JavaScript on the browser, occasionally we see that frames are missed, which does not provide a great User Experience.

We have heard that Web Workers is one of the promising solutions to such a problem, but we never knew that it was so easy to introduce it to our Angular Application using Angular CLI.

Angular CLI v8.0.0-beta.11 added improved bundling support for Web Workers without you needing to add any new configuration. In this article, we will create an application in which we will run heavy calculations of checking if a list of more than 600 numbers are prime numbers or not.

Let’s create a new Angular CLI application using v8.0.0-beta.11 with npx command.

> npx -p @angular/cli@next ng new prime-numbers
Enter fullscreen mode Exit fullscreen mode

Adding Web Workers is as easy as generating components, services, etc. using ng generate command.

> ng generate worker prime-calculations
CREATE src/tsconfig.worker.json (209 bytes)
CREATE src/tsconfig.json (131 bytes)
CREATE src/app/prime-calculations.worker.ts (121 bytes)
UPDATE tsconfig.app.json (232 bytes)
UPDATE angular.json (3558 bytes)
Enter fullscreen mode Exit fullscreen mode

This will add a file called prime-calculations.worker.ts in the app folder along with the other changes that are required for web workers setup (only done once).

Now that we have our worker file, let’s first install a package prime-number that can check if a number is a prime number, and also has a list of 600+ prime numbers.

> npm install prime-number
Enter fullscreen mode Exit fullscreen mode

The operation that we want to execute in both JavaScript thread and Web Worker is the following, where we loop over the primeNumberList and check if they're a prime number or not by using the method isPrimeNumber

import isPrimeNumber from 'prime-number';
import primeNumberList from 'prime-number/list';
const arePrimeList = primeNumberList.map((prime) => {
    return isPrimeNumber(prime);
});
Enter fullscreen mode Exit fullscreen mode

Let’s add two buttons, one to run the logic in the worker, and another one in the main thread.

<button (click)=”runWorker()”>Web Worker</button>
<button (click)=”runThread()”>JavaScript Thread</button>
Enter fullscreen mode Exit fullscreen mode

Now let’s add both methods to our AppComponent class.

import isPrimeNumber from 'prime-number';
import primeNumberList from 'prime-number/list';
...
export class AppComponent {
    title = 'web-worker';
    runWorker() {
       const worker = new Worker('./prime-calculations.worker', { 
           type: 'module' 
       });
       worker.onmessage = ({ data }) => {
           console.log('From Web Worker:', data);
       };
       worker.postMessage({});
    }
    runThread() {
        const arePrimeList = primeNumberList.map((prime) => {
            return isPrimeNumber(prime);
        });
        console.log('From Javascript Thread', arePrimeList);
    }
}
Enter fullscreen mode Exit fullscreen mode

The runThread method is just doing calculations right in the method, but in runWorker, we are creating a new worker, and listening to onmessage, and then posting a message using worker.postMessage()

Now let’s update our worker prime-calculations.worker.ts with the same logic,

import isPrimeNumber from 'prime-number';
import primeNumberList from 'prime-number/list';
addEventListener('message', ({ data }) => {
    const arePrimeList = primeNumberList.map((prime) => {
        return isPrimeNumber(prime);
    });
    postMessage(arePrimeList);
});
Enter fullscreen mode Exit fullscreen mode

Here we listen to the message and then run the same prime calculations that we did in the JavaScript thread.

Now that both methods are doing the same calculations, let’s see how our app reacts when a user clicks on each button.

Image for post

Here we clearly see the lag when the JavaScript Thread button was clicked. When we clicked on the Web Worker button we did not see any delay. That happened because the Web Worker runs in a separate thread and does not block the main thread.

Conclusion:

Angular is not just a framework but it’s a platform. Angular’s tooling, especially Angular CLI is exceptional and it is what makes developing Angular Apps much easier.

👋 Hi! I’m Zama Khan Mohammed. I work at Tekzenit as a Software Architect — Web Technologies. I’m actively involved in working on Projects using Angular, React and Serverless Technologies along with writing a book “Angular Projects”.

For more Angular goodness, be sure to check out the latest episode of The Angular Show podcast.


ng-conf: Join us for the Reliable Web Summit

Come learn from community members and leaders the best ways to build reliable web applications, write quality code, choose scalable architectures, and create effective automated tests. Powered by ng-conf, join us for the Reliable Web Summit this August 26th & 27th, 2021.
https://reliablewebsummit.com/

Discussion (0)