ANDRII DATSENKO <ASDatsenko@luxoft.com>

TECHNICAL LEAD

May 17, 2017

OFFLINE w/ ServiceWorkers

 ERR_INTERNET_DISCONNECTED

SERVICE WORKERS

A service worker sits between your site and the network.

Page

SW

Network

OFFLINE EXPERIENCE

One component of Progressive Web Apps

PROGRESSIVE
WEB APP

  • Fast Performance

  • Instant Content Load

  • Push Notifications

  • Add to Home Screen

WEB WORKER

Service Workers are just one type of Worker. Web Workers in the browser allow us to run code in a separate worker thread.

NEW THREAD

JavaScript is a single threaded. However sometimes we need to do more than one thing at a time.

REGISTER SW

if('serviceWorker' in navigator) {
    navigator.serviceWorker.register('./sw.js')
        .then(reg => {
            console.log('Service Worker Registered')
        })
        .catch(err => {
            console.log(`Error registering worker ${err}`);
        })
}

SW SCOPE

navigator.serviceWorker.register('./sw-api.js', { scope: '/api/' });

navigator.serviceWorker.register('./sw-assets.js', { scope: '/assets/' });

/assets/ Matches

  • /assets/
  • /assets/foo
  • /foo/assets/
  • /foo/assets/1

DEBUG

LIFECYCLE

Install

Active

INSTALL

self.addEventListener('install', function(e) {
  caches.open('app-name')
    .then((cache) => {
            
    });
});

CACHE ALL

return cache.addAll([
  '',
  'js/script.js',
  'css/style.css'
]);

Files have to be available!!

INTERCEPT REQUESTS

self.addEventListener('fetch', function(e) {
  e.respondeWith(
    caches.open('union-times')
      .then((cache) => {
        return caches
          .match(e.request)
          .then((res) => res);
      });
    })
  );
});

INTERCEPT REQUESTS

return caches.match(e.request)
  .then(function(res) {
    return res || fetch(e.request).then(res => {
      cache.put(e.request, res.clone());
      return res;
    });
});

FREQUENT UPDATES?

NETWORK FIRST

self.addEventListener('fetch', function(e) {
  e.respondWith(
    fetch(e.request)
      .then((response) => networkThenCache(response,e))
      .catch(() => pullFromCache(e))
  );
});

NETWORK FIRST

function networkThenCache(response,e) {
  return caches.open(cacheVersion)
    .then(function(cache) {
      return caches.match(e.request)
        .then(function(res) {
          cache.put(e.request, response.clone());
          return response;
        });
    });
}

Optimistic

NETWORK FIRST

function pullFromCache(e) {
  return caches.open(cacheVersion)
    .then(function(cache) {
      return caches.match(e.request)
        .then(function(res) {
          return res;
        });
    });
}

Pessimistic

CACHE CLEANUP?

CLEAR ON ACTIVATED

const cacheVersion = 'app-name-2.0.0';

self.addEventListener('activate', function(e) {
  e.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames
          .filter((name) => name === cacheVersion)
          .map((cache) => caches.delete(cache))
        );
      })
    })
  );
});

SW-TOOLBOX

toolbox.precache([
  '/index.html', 
  '/site.css',
  '/images/logo.png'
]);



toolbox.router.get(':foo/index.html', function(request, values) {
  return new Response('Handled a request for ' + request.url +
      ', where foo is "' + values.foo + '"');
});

toolbox.router.post('/(.*)', apiHandler, {
  origin: 'https://api.example.com'
});

LINKS

Q&A Time

ANDRII DATSENKO <ASDatsenko@luxoft.com>

TECHNICAL LEAD

May 17, 2017

OFFLINE w/ ServiceWorkers

 ERR_INTERNET_DISCONNECTED

Offline experience with ServiceWorkers

By Andrew Dacenko

Offline experience with ServiceWorkers

  • 1,541