JMM’s notes on

Service Workers


Can I use DOMParser in service workers?

Doesn’t seem like it. I tried on 2024-02-01 using Firefox’s about:debugging, inspecting a running service worker, and trying to type “DOMParser” at the console. No luck.

This comment from annevk suggests it’s not accessible because DOM implementation aren’t thread-safe.

Can a service worker uninstall itself

Imagine that a service worker doesn’t work on some browser (like, it’s an old browser that doesn’t support some new web feature, or it’s just Safari on iOS). Can I write a service worker in a way that’ll catch unexpected errors and have it uninstall itself and prevent reinstallation of the same version?


Yes, a service worker can uninstall itself, though it’s better to say that it can “unregister” itself. You can run


inside a service worker to unregister it. It only takes affect after controlled clients are unloaded. See the unregister() section of the Service Workers spec.

Unanswered questions

That is, I haven’t looked up or tried to answer them yet.

  • If a Service Worker calls fetch, does that fetch use the HTTP cache? Or is the HTTP cache now bypassed entirely (essentially removing the effect of the Cache-Control header)?
  • Will HTTP requests with If-Not-Modified still occur?
  • Is it possible to look up some stateful information in a fetch handler without using a respondWith? I’ve heard that passthrough respondWith is “bad” (why?), but it seems like I need to use respondWith if I’m using asynchronous APIs like IndexedDB.
    • One thing I could do is start immediately fetching stateful data from some IndexedDB during initialization of the service worker. Then, once initialized, some global (to the service worker) var that starts off null or undefined could be updated with a value. This would only persist until the worker is killed.

    • Another option might be to only add the fetch event listener once stateful data is loaded. However, will this actually work? Does a service worker allow attaching event handlers later in some asynchronous operation?

    • Third option, like the first, would be to have two versions of the fetch event handler, which is bound to some var. After stateful data is loaded, the initial event handler is swapped out with a second one.

  • mentioned that Firefox doesn’t correctly handle Range requests. Is this still true?
  • If a Service Worker passes through a Range request for some video, will it attempt to cache everything? Can it be interrupted? Typically Firefox will find a video supports Range headers and will only load parts of videos (more or less).
  • I’ve read the Service Workers can be killed essentially at any time if they’re using too much resources. How much is too much? How likely is this to occur?
  • When fetching from self.caches, if a request matches multiple caches, what’s the order of listing (if defined at all)?
  • I know that correctly setting the Vary header becomes important once you start using service workers, as it affects cache request matching. What are the specifics of that?
  • A service worker can make a controlled client navigate to another location. Can it make a controlled client load some JavaScript if no JavaScript had yet been loaded?

    For example, a static article without JS is loaded from cache. In the background, a new version of the article is fetched. Is there a good way a service worker can notify the user that they may want to refresh?

  • How do hard refreshes (like Control+Shift+R) interact with service workers?


Installation fires but not activation

I noticed that the “install” event was being triggered, but not the “activate” event for a service worker I was developing. Turns out that the “install” event was failing. I had a cache.addAll, and one of the resources returned a 404, causing the promise to reject. Because this promise was used by event.waitUntil, the installation also failed.

BroadcastChannel for debugging

Just a tip: One way to debug service workers without switching to about:debugging is to have the service worker use a BroadcastChannel to send messages to other windows.