Service Workers vs Web Workers

June 04, 2020

Progressive web apps or PWAs are a hot new topic and an exciting frontier for frontend developers. They provide incredible potential to change what users expect from web applications. When diving into PWAs, service workers are often front and center and for good reason. They are at the heart of PWAs and the offline capabilities they add are what makes PWAs magical. However when starting with PWAs it's easy to get confused about what to use Service Workers for and what the less commonly discussed Web Workers are for.

As I was learning about PWAs, I initially thought I should be doing all of my asynchronous processing in the service worker. There is some good documentation explaining what both Service Workers and Web Workers can do, but I found few examples explaining how PWAs should be using each one and why. Hopefully this brief guide will keep others from having to learn by trial and error like I did.

Service Workers

The best definition I have seen is from from MDN.

Service workers essentially act as proxy servers that sit between web applications, the browser, and the network (when available). They are intended, among other things, to enable the creation of effective offline experiences, intercept network requests and take appropriate action based on whether the network is available, and update assets residing on the server. They will also allow access to push notifications and background sync APIs.

To summarize, use service workers to:

  1. Intercept network requests when the network is unavailable.
  2. Handle push notifications
  3. Sync data to and from the server in the background.

The advantage of using a Service Worker for push notifications and background sync is, unlike a Web Worker, it isn't connected to the page lifecycle. So a page refresh won't cause the Service Worker task to be interrupted.

The biggest gotcha that I found was in the complexity of the lifecycle and how it affects development. You think you're running the latest code and wonder why you're not seeing updates when really you're not. The best way to mitigate the Service Worker lifecycle headaches were by making extensive use of the developer tools in both Chrome and Firefox. They provide easy ways to stop, start and reinstall the Service Worker to be sure you have the latest code running.

Web Workers

Again from MDN:

Web Workers makes it possible to run a script operation in a background thread separate from the main execution thread of a web application. The advantage of this is that laborious processing can be performed in a separate thread, allowing the main (usually the UI) thread to run without being blocked/slowed down.

To summarize, Web Workers should be used to do any long running asynchronous processing. Web Workers spawn as separate OS threads so they don't slow down the UI responsiveness. As I mentioned above, Web Workers are tied to the page lifecycle which means a refresh will kill your Web Worker.

The main hurdle I had with using a Web Worker was using external libraries in the Web Worker. In my case, I was processing images and needed to use a few third party libraries to optimize and resize the images and also to read the EXIF data. See my blog post here explaining how I went about doing that.

Boiling it all down to one question

A helpful paradigm I've found as you're considering whether to do a task in a Web Worker or in the Service Worker is: does the user expect this task to be performed and to wait on its completion? If the answer is yes, use a Web Worker. If not, many times the user may not know the task is even taking place, an example being background sync to the server. In that case, you would most likely use a Service Worker.

I hope this has helped you have a better grasp of Service Workers and Web Workers. Thanks for reading!