Playing Hide & Seek With My Service Worker Instance!

If you are working with Service Workers for the first time you'll probably have noticed that the Service Worker's functionality can be found on different objects. This can be a little bit confusing.

In this article:

First of all the API is a little bit misleading because navigator.serviceWorker is not an instance of the Service Worker itself – it’s only a container. The Service Worker itself is provided by the property controller of this ServiceWorkerContainer.
  • navigator.serviceWorkerServiceWorkerContainer
  • navigator.serviceWorker.controllerServiceWorker
And there’s also the ServiceWorkerRegistration that’s not accessible as a property but can be accessed by different methods. Let’s start with the ServiceWorkerContainer! It allows you to access the current Service Worker and also allows you to receive messages from it in your application.
				
					navigator.serviceWorker.addEventListener('message', event => {
    console.log('Message from service worker received: ', event.data);
});
				
			

The ServiceWorkerContainer also allows you to register a new Service Worker. The register() method responds with a promise that resolves with a ServiceWorkerRegistration object if the registration was successful. If there’s already a registered Service Worker you will get the current ServiceWorkerRegistration – otherwise a new one.

				
					navigator.serviceWorker.register('serviceWorker.js', registration => {
    console.log('Service worker successfully registered');
});

				
			

The ServiceWorkerRegistration represents – as the name reads – the registration of the Service Worker. Besides the register()-method this registration can also be accessed in other ways:

  • navigator.serviceWorker.ready(): The returning promise of this method will never be rejected and waits until the Service Worker is ready.
  • navigator.serviceWorker.getRegistration(scope): Returns a promise that resolves with the Service Worker registration of your specific scope (usually given as relative url but also optional). If no registration is available the promise resolves with undefined.
  • navigator.serviceWorker.getRegistrations(): Returns a promise that resolves with an array of all active Service Worker registrations. If there’s no active registration the promise will resolve with an empty array.

The serviceWorkerRegistration allows you to access several APIs and functions you can use to improve your web application (only a few examples):

On the registration.active-property you have access to the active Service Worker. This is an instance of the ServiceWorker-interface. This object is the instance that controls your site and also your network requests. If a Service Worker is registered for the first time it won’t control your site instantly and a reload of the page is necessary.

The active Service Worker is also accessible with window.navigator.controller but be careful! If you force a page reload this property is null. The property will also be null if there’s no active Service Worker – registration.active is still available and gives you the last value set as active Service Worker. But why do you need your active Service Worker? The Service Worker is necessary if you want to send messages to your Service Worker instance and communicate with your Service Worker.

				
					navigator.serviceWorker.controller.postMessage(data);
				
			

Also you can watch state changes of the Service Worker on its instance.

				
					navigator.serviceWorker.controller.onstatechange = event => {
    const serviceWorker = navigator.serviceWorker.controller;
    console.log('Current service worker state: ', serviceWorker.state);
};
				
			

As you see there are different ways to access your Service Worker functionality and the naming isn’t clear all the time. The Service Worker specification is still a draft at W3C and so it maybe changes and becomes more clear when the specification is finished. I hope I was able to bring a little light into the darkness and it is a little bit clearer now.

Stay tuned and have fun. 🙂

More articles about PWA, JavaScript
Free
Newsletter

Current articles, screencasts and interviews by our experts

Don’t miss any content on Angular, .NET Core, Blazor, Azure, and Kubernetes and sign up for our free monthly dev newsletter.

EN Newsletter Anmeldung (#7)
Related Articles
.NET
KP-round
.NET 8 brings Native AOT to ASP.NET Core, but many frameworks and libraries rely on unbound reflection internally and thus cannot support this scenario yet. This is true for ORMs, too: EF Core and Dapper will only bring full support for Native AOT in later releases. In this post, we will implement a database access layer with Sessions using the Humble Object pattern to get a similar developer experience. We will use Npgsql as a plain ADO.NET provider targeting PostgreSQL.
15.11.2023
.NET
KP-round
Originally introduced in .NET 7, Native AOT can be used with ASP.NET Core in the upcoming .NET 8 release. In this post, we look at the benefits and drawbacks from a general perspective and perform measurements to quantify the improvements on different platforms.
02.11.2023
.NET
KP-round
.NET 8 introduces a new Garbage Collector feature called DATAS for Server GC mode - let's make some benchmarks and check how it fits into the big picture.
09.10.2023