sw-precache icon indicating copy to clipboard operation
sw-precache copied to clipboard

navigator.serviceWorker.controller: Different behavior between Chrome and FireFox?

Open sondreb opened this issue 8 years ago • 5 comments

Having some issues with handling in the "installed" state changed on the service worker. They appear to behave differently in Chrome and FireFox.

installingWorker.onstatechange = function () {
	switch (installingWorker.state) {
		case 'installed':
			if (navigator.serviceWorker.controller) {

On Chrome, the .controller exists, while on FireFox, it does not (at least not at that time).

In the sample provided on this repo, it is stated:

// At this point, the old content will have been purged and the fresh content will
                // have been added to the cache.
                // It's the perfect time to display a "New content is available; please refresh."
                // message in the page's interface.
                console.log('New or updated content is available.');

https://github.com/GoogleChrome/sw-precache/blob/master/demo/app/js/service-worker-registration.js

While looking at the sample on Mozilla Developer site, the logic looks switched?

if (navigator.serviceWorker.controller) {
      document.querySelector('#status').textContent = 'A service worker is currently handling network operations.';
    } else {
      document.querySelector('#status').textContent = 'Please reload this page to allow the service worker to handle network operations.';
    }

https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/controller

I want to show a dialog to the user that update is installed, which has a reload button.

In my tests, the dialog appears on Chrome but not FireFox. I did have dev tools open in both browsers to look at the console logging when I did the test, perhaps this affects the behavior? None of the checkboxes on the Application tab in Chrome was checked.

sondreb avatar Jun 09 '17 07:06 sondreb

This behavior was on test-server, when running locally with "ng serve" and manually modifying the service-worker.js, I get the correct expected behavior in both Chrome and FireFox the first time I start, but second time it fails on FireFox. ... strange.

sondreb avatar Jun 09 '17 08:06 sondreb

During testing, I have some logic that checks the manifest.json for a new version. If a new version is found, I find the service worker registration and call .update().

At which time, Chrome will install and .controller will be set. FireFox will not have .controller set, but all the installed, activating and activated events are called.

If I now, without reloading yet, modifies the service-worker.js again, FireFox will again trigger the installed state change and THEN the .controller is set. FireFox will also log an "redudant" state change at that time.

Here is a fix that appears to work for FireFox, when using a timeout:

installingWorker.onstatechange = function () {
	switch (installingWorker.state) {
		case 'installed':
			setTimeout(function () {
				if (navigator.serviceWorker.controller) {
					// This now works for Chrome and FireFox
				}
			}, 200);

sondreb avatar Jun 09 '17 08:06 sondreb

It worked with timeout of 200ms, it does not work with no set timeout. I'll leave it at 5 seconds, to make sure FireFox have initialized the object properly.

sondreb avatar Jun 09 '17 08:06 sondreb

I have observed this exact same issue. I have a problem where requests are not always passed to service worker fetch even though service worker is installed.

Is it possible that this could be caused when page reload is made in case 'installed' but before navigator.serviceWorker.controller is defined?

To get this work on Firefox (Quantum 60.0 / Win10) I need to reload page manually even though I've already reloaded programmatically in case 'installed' too. This also applies to Edge 42.17134.10.

In case 'installed':

  1. before programmatical reload is done navigator.serviceWorker.controller is defined
  2. after programmatical reload is done navigator.serviceWorker.controller is UNDEFINED
  3. after manual reload is done navigator.serviceWorker.controller is defined

In Chrome (66.0) 1) and 2) seems to be exactly the opposite

@jeffposnick any ideas?

EDIT: it seems that doing location.reload(false); instead of location.reload(true); as step 2 fixes the controller being UNDEFINED for Firefox and Edge (but not the fact that step 1) behaves differently in Chrome vs. Firefox/Edge)

Also for Chrome reload(false) / reload(true) does not seem to make a difference.

jukkasi avatar May 15 '18 07:05 jukkasi

location.reload(true) is meant to indicate that you want a hard-refresh: https://developer.mozilla.org/en-US/docs/Web/API/Location/reload

Service workers are disabled during a hard refresh when triggered by Shift + Reload: https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle#shift-reload

I guess Chrome and Firefox behave differently w.r.t. whether location.reload(true) should disable service workers or not.

jeffposnick avatar May 17 '18 18:05 jeffposnick