Improve Performance with Web Workers

erxk

Erxk

Posted on June 19, 2019

Improve Performance with Web Workers

Using the Angular 8 CLI

Introduction

This article will illustrate how to improve start-up performance using Web Workers. Our example will be an Angular 8 application. Using the Angular 8 CLI simplifies getting started with Web Workers. However, using Web Workers is not specific to Angular and most of these concepts can be utilized in any Javascript or Typescript application.

Download the Source Code 🚀

We will cover

  • Measuring Performance in Lighthouse
  • Getting Started with Web Workers in Angular 8 [1]
  • Measuring Performance with Web Workers
  • Web Worker Limitations and Pitfalls

Measuring Performance with Lighthouse

First, we need to get a baseline measurement to gauge how performant our application is on start-up without a Web Worker. Note, we are running our Angular application in production mode — This affects start-up performance.

In the Google Chrome Developer Tools đź› , using Lighthouse, we can measure the performance of our webpage on startup [2]. I have added a long-running task/computation to the startup of our application (for-loop building a massive string).

Performance without Web Worker

When we execute a long-running task on the Main thread, our application appears to be locked up. This is because the Main thread is blocked by all of the computations in our long-running task. Thus, the user cannot interact with our application until the process has finished.

By clicking “View Trace”, we can see a visualization of CPU time on start-up. In our example, the majority of the time spent was evaluating/running our script/task. We can also verify in the trace that our code is running in the Main thread.

Performance without Web Worker

Getting Started with Web Workers

The Angular 8 CLI has simplified getting started with Web Workers. To create a Web Worker, we will simply run the Angular 8 web-worker schematic.

Generate a Web Worker

The name and location of the worker are mostly arbitrary. A caveat, if your Web Worker has the same name and folder as your component, Angular will automatically add the following code to your component for you. If not, add this code where you want to use the worker.

The only other code generated is the actual worker itself. This is where we will move our long-running computations to.

Main thread → Web Worker → Main thread

When our Web Worker invokes worker.postMessage('hello') the content inside our 'message' event listener will execute inside the Worker. Once our task has completed, postMessage(response) will be called from the Web Worker and worker.onmessage(data)=> {} will execute inside our component back in the Main thread.

Web Worker Performance

Once we move our long-running task to the Web Worker inside of addEventListener('message', (data)=> { // Here }); we will be ready to test our performance again. Note, we will cover various limitations when executing code in a Web Worker later. For now, we simply move our code from the component to the Web Worker.

We can see that the performance of our application on start-up has significantly improved. This is because the Main thread only takes 1.8s before its finished evaluating our Javascript and rendering our components on the screen.

When our long-running task was in the Main thread, we had to wait the additional time to complete the long-running task before the application became interactive.

Performance with Web Worker

The application stays interactive the entire time our script/task is running, as it is not on the Main thread. Performing a “View Trace” we can verify that our script/task is running in an instance of our Worker and the Main thread is sitting idle.

Performance with Web Worker

Web Worker Limitations & Pitfalls

Cannot Pass Functions to Web Workers

Functions and methods cannot be passed to Web Workers. When an object is passed to a Web Worker, all of its methods are removed. If a function is passed to a web worker, the following exception will occur.

worker.postMessage(() => {return 'hello'});
Enter fullscreen mode Exit fullscreen mode

Working with DOM & window

Web Workers run in a different global context than window. DOM manipulation is not allowed, and some methods and properties of the window are not available in web workers. [3]

Running very large processes

In general, there is not a significant difference in time to complete a task when running in Main or in a Web Worker. If you run very large processes inside of a Web Worker, there is a point where the Web Worker becomes significantly slower than the Main thread.

In our example, if we increase the number of iterations significantly, we can see the difference in performance changes dramatically.

Smaller Dataset: 19ms | 37ms

Larger Dataset: 13s | 39s

Summary

  • Measure the performance of an application on start-up using Lighthouse in Google Chrome Developer Tools.
  • Long-running tasks/computations in the Main thread will cause the UI to lock and become unresponsive
  • Delegate long-running tasks to Web Workers to improve performance
  • Angular 8 CLI simplifies getting started with Web Workers
  • Be aware of limitations and pitfalls when working with Web Workers

References

[1] https://angular.io/guide/web-worker

[2] https://developers.google.com/web/tools/lighthouse/

[3] https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers

đź’– đź’Ş đź™… đźš©
erxk
Erxk

Posted on June 19, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related