So, i’ve been researching about Web Workers since they were just a cool concept, but i had trouble finding a real use case where i really “needed” a Web Worker in my Angular apps.

Let’s be honest here. ¿How many times we need to calculate a Fibonacci sequence, or calculate an n-factorial in a real world app? ¿How many of us do really use Javascript to create games with complex physics calculations?

Yeah.. Almost never.

But a few months ago, i had a simple use case i needed to resolve for one of my apps.

Given a photo taken by the user, i needed to compress such photo, up to certain max width/height and then send it to the backend.

¿Sounds simple, right?. Indeed its a simple task. I just installed a lib called Jimp.

npm install — save jimp

all it takes to resize an image with Jimp is to create a jimp object, then call the resize method with height and width as parameters, and then optionally i can reduce the quality to get some extra compression done.

So, that’s all it takes, the code writing part is not the problem. The real problem is that this simple task is very heavy lifting for our single thread based javascript architecture, so it has to either keep working on rendering our screen, or do the math for the image resizing and “freeze” the UI, and given the fact that compressing our 15MP photo is a task that can take a few seconds, specially in low end mobile phones, i needed to show my users some kind of loading indicator.

To make our problem a little more easy to replicate i made a very simple angular app whose entire function is to show some kind of a big picture on the screen, and then let us resize and compress it in a non ui-blocking way.

The Problem

So, let’s start with an empty Angular project

ng new jimp-webworker

First, we need an image. To make it really simple, i created a constant called UNCOMPRESSED_IMAGE which stores the Base64 encoded version of the image.

So our first version of the AppComponent class could look like this

Nothing fancy, just plain old displaying a Base64 Image on our view, we need to sanitize it, and then render it inside an <img>. I also added a small loader, it will be active all the time to show us the status of our UI during the compression process.

If we serve our app we will see this on the screen.

Let’s add the image compression logic.

To keep this simple, i won't dive too deep into the logic. All we need to know is that it gives us a compressImage method that receives a Base64 encoded image as input, and returns a Promise, that when resolved, contains the compressed version of the image as result.

Now we are going to create a simple Angular Service, that will consume our little util function, and will provide a compress method, that will return an Observable of the compressed image. After that, we declare our newborn service in our AppModule, and then inject it into our AppComponent.

Now we can update our AppComponent compress method to make it call the compressImage method from our service, and render the result on the screen.

Great! Now it's time to test it!!

Ughhh, that doesn't look right. The UI froze completely while the image was being compressed.

Web Workers to the rescue

Ok, don't worry. There is a solution for that nasty looking UI freezing problem: The Web Worker. A Web Worker is a script that runs on a different thread than the UI, and can communicate with the main thread using messages. What we want to achieve is to send the uncompressed Base64 image to the Web Worker, and the WW will send the compressed Base64 to the main thread using a message.

The angular cli gives us a WW generator, so we will use it:

ng g web-worker jimp

The command will create a jimp.worker.ts file on the src folder, we will modify such file and add our logic:

And then we need to modify our Service to use the WW:

Finally lets call our new service method inside the AppComponent:

And now, the moment of the truth… Let's test it!

Super smooth!!

As you see, Web Workers are a really cool feature, and with Angular 8 they are very easy to implement.

If you want to take a look at the full source of this demo, its available at:

If you enjoyed my story or want to give me feedback, you can reach me on https://twitter.com/EzequielZacca