Using Angular with WebWorkers
Multithreading is a common technique for improving the performance of applications. By splitting workloads into separate threads, makes it possible to utilize multiple CPU cores to speed up processing.
One way to implement multithreading in web applications is by using Web Workers.
Web Workers allow scripts to run in the background without blocking the main thread, improving performance and responsiveness.
What Are Web Workers?
Web Workers are a way to run JavaScript code in a separate thread from the browser’s main thread. This allows for background processing without blocking the UI thread, which can improve performance and responsiveness. Web Workers have access to a subset of the browser’s APIs, including communicating with the main thread via messages.
There are two types of Web Workers:
- Dedicated Workers: Are created for a specific script and can only be accessed by that script.
- Shared Workers: Can be accessed by multiple scripts and can communicate with any window or worker that has the same origin.
Why Use Web Workers in an Angular Application?
Angular applications are typically single-threaded, which means that all processing is done on the browser’s main thread. This can lead to slow performance and a poor user experience. By using Web Workers, we can offload processing to separate threads and improve performance.
Web Workers can be used in an Angular application for a variety of tasks, including:
- Complex computations, such as data analysis or machine learning
- Image and video processing
- Background tasks, such as syncing data or sending notifications
Should mostly be used in applications, not libraries
How to Use Web Workers with Angular
Using Web Workers with Angular is straightforward.
Create a new Web Worker file.
This file should contain the code you want to run in the background.
// typescript data.worker.ts
addEventListener('message', ({ data: unknown }) => {
const result = processData(data);
postMessage(result);
});
function processData(data: unknown) {
// process the data here
return result;
}
In this example, you are listening to messages from the main thread and processing data when a message is received.
The result is sent back to the main thread when the processing is complete.
Create the relevant tsconfig file to support this worker:
// tsconfig.worker.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/worker",
"lib": ["es2018", "webworker"],
"types": []
},
"include": [
"src/**/*.worker.ts"
]
}
Make sure your angular.json is aware of this file:
{
…
"projects": {
…
"myProj": {
…
"architect": {
"build": {
…
"webWorkerTsConfig": "tsconfig.worker.json"
}
…
}
}
}
}
This all can be done with CLI using:
ng generate web-worker <location>
Next, Create a new Worker instance in your Angular component. This can be done using the Worker constructor, like this:
At the component (or service calling the worker)
const worker = new Worker('./data.worker', { type: 'module' });
This code creates a new Web Worker instance with the file data.worker.ts.
Messages can be sent to the worker using the postMessage method, like this:
worker.postMessage(data);
Act when the messages return with the onmessage, like this:
worker.onmessage=({ data: unknown }) => {
console.log(data);
};
This message is handled by the worker using the addEventListener method you have in the worker file.
Reminder:
addEventListener('message', ({ data: unknown }) => {
const result = processData(data);
postMessage(result);
});
Best Practices for using WebWorkers in Angular
When using Web Workers in an Angular application, consider the following best practices:
- Isolate Business Logic: Move computationally intensive tasks, heavy data processing, or time-consuming operations to Web Workers. This ensures that the main thread remains responsive and improves overall performance.
- Keep Communication Minimal: Minimize the frequency and size of messages exchanged between the main thread and Web Workers. Excessive communication can introduce overhead and negate the benefits of using Web Workers.
- Error Handling: Implement proper error handling mechanisms in Web Workers to handle exceptions and notify the main thread when errors occur. Consider using the onerror event listener to capture unhandled errors in Web Workers.
- Fallback for Unsupported Browsers: Web Workers are supported in all modern browsers, but it’s good practice to check for browser compatibility and provide fallback options for unsupported browsers. You can use feature detection or a polyfill to ensure a consistent browser experience.
Do You Ask Yourself Can’t I Just Run Outside `ngZone`?
As you know, Angular applications use ngZone to manage change detection and ensure that UI updates are triggered appropriately.
Running outside ngZone, still uses the same thread, and simply ignores the default change detection used by Angular.
When running code within a Web Worker, it operates outside the ngZone, and also keeps the main thread from blocking.
Considerations:
Manual Change Detection: When the Web Worker completes its task and sends a message back to the main thread, it’s essential to manually trigger change detection to update the UI. This can be done using Angular’s ChangeDetectorRef or by leveraging zone.run() to explicitly trigger change detection.
Note: It’s crucial to strike a balance between utilizing Web Workers for performance gains and ensuring that UI updates are reflected correctly by considering when and how to trigger change detection in Angular components.
Conclusion
Web Workers provide a powerful tool for improving web applications’ performance in web Applications in general. By offloading computationally intensive tasks to separate threads, you can enhance responsiveness and user experience. Remember to follow best practices, such as isolating business logic, minimizing communication, and handling errors properly. Be mindful of the differences in change detection when using Web Workers outside of ngZone, and ensure that UI updates are triggered appropriately.
Incorporating Web Workers into your Angular application opens up new possibilities for handling complex computations, data processing, and background tasks. Experiment with Web Workers and discover how they can elevate the performance of your Angular application while delivering a smooth and responsive user interface.
Happy coding!