Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practices for detecting offline state in a service worker

I have a service worker that is supposed to cache an offline.html page that is displayed if the client has no network connection. However, it sometimes believes the navigator is offline even when it is not. That is, navigator.onLine === false. This means the user may get offline.html instead of the actual content even when online, which is obviously something I'd like to avoid.

This is how I register the service worker in my main.js:

// Install service worker for offline use and caching if ('serviceWorker' in navigator) {   navigator.serviceWorker.register('/service-worker.js', {scope: '/'}); } 

My current service-worker.js:

const OFFLINE_URL = '/mysite/offline'; const CACHE_NAME = 'mysite-static-v1';  self.addEventListener('install', (event) => {   event.waitUntil(     // Cache the offline page when installing the service worker     fetch(OFFLINE_URL, { credentials: 'include' }).then(response =>       caches.open(CACHE_NAME).then(cache => cache.put(OFFLINE_URL, response)),     ),   ); });  self.addEventListener('fetch', (event) => {   const requestURL = new URL(event.request.url);    if (requestURL.origin === location.origin) {     // Load static assets from cache if network is down     if (/\.(css|js|woff|woff2|ttf|eot|svg)$/.test(requestURL.pathname)) {       event.respondWith(         caches.open(CACHE_NAME).then(cache =>           caches.match(event.request).then((result) => {             if (navigator.onLine === false) {               // We are offline so return the cached version immediately, null or not.               return result;             }             // We are online so let's run the request to make sure our content             // is up-to-date.             return fetch(event.request).then((response) => {               // Save the result to cache for later use.               cache.put(event.request, response.clone());               return response;             });           }),         ),       );       return;     }   }    if (event.request.mode === 'navigate' && navigator.onLine === false) {     // Uh-oh, we navigated to a page while offline. Let's show our default page.     event.respondWith(caches.match(OFFLINE_URL));     return;   }    // Passthrough for everything else   event.respondWith(fetch(event.request)); }); 

What am I doing wrong?

like image 833
Kaivosukeltaja Avatar asked Sep 04 '17 12:09

Kaivosukeltaja


People also ask

How do I find out if a service worker is running?

A: From a page on the same origin, go to Developer Tools > Application > Service Workers. You can also use chrome://inspect/#service-workers to find all running service workers.

How do you manipulate DOM using a service worker?

So what you need to do, is send message from service worker to document javascript with list of id/class/tagname/whatever of DOM elements that you want to manipulate, and let main thread do the job.

Can service workers access local storage?

Note: localStorage works in a similar way to service worker cache, but it is synchronous, so not allowed in service workers.


Video Answer


1 Answers

navigator.onLine and the related events can be useful when you want to update your UI to indicate that you're offline and, for instance, only show content that exists in a cache.

But I'd avoid writing service worker logic that relies on checking navigator.onLine. Instead, attempt to make a fetch() unconditionally, and if it fails, provide a backup response. This will ensure that your web app behaves as expected regardless of whether the fetch() fails due to being offline, due to lie-fi, or due to your web server experiencing issues.

// Other fetch handler code...  if (event.request.mode === 'navigate') {   return event.respondWith(     fetch(event.request).catch(() => caches.match(OFFLINE_URL))   ); }  // Other fetch handler code... 
like image 152
Jeff Posnick Avatar answered Sep 20 '22 15:09

Jeff Posnick