[Viktor Zozuliak] Service Worker - Native Apps Experience For The Web

[Viktor Zozuliak] Service Worker - Native Apps Experience For The Web

Presentation from GDG DevFest Ukraine 2015 - the biggest Google related event in the country. October 23-24, Lviv. Learn more at http://devfest.gdg.org.ua/


Google Developers Group Lviv

October 24, 2015


  1. Native Apps Experience For The Web Service Worker Viktor Zozuliak

    Front-End Developer @ DataXu/RailsReactor
  2. Who is mr. Service Worker?

  3. #dfua Who is mr. ServiceWorker? Service Worker - is a

    new JavaScript API, special type of Web Worker Web Worker - script running in background in separate thread
  4. What Is The Purpose Of Service Worker?

  5. #dfua What is the purpose of ServiceWorker? To fill the

    gap between web and native apps in context of offline-first and background operations.
  6. What Is Offline First?

  7. #dfua What Is Offline First? It is about not treating

    offline like an error
  8. Offline First VS Offline As Error

  9. #dfua Facebook - News Feed Offline as error ☹ ☹

    ☹ Offline first☺☺☺
  10. #dfua Facebook - Commenting Offline as error ☹ ☹ ☹

    Offline first☺☺☺
  11. Previous Solution - App Cache (Cache Manifest)

  12. #dfua Cache Manifest • Allows to cache only GET requests

    • Only full cache update - no individual record updates • No possibility to add switching logic between network and cache • ==> Deprecated!
  13. What Service Worker Offers?

  14. #dfua What Service Worker Offers? • making apps available offline

    - install/update • full control over app caches • full control over network requests • subscribing to push notifications • background synchronization
  15. Service Worker Lifecycle

  16. #dfua Service Worker Lifecycle • register • install • wait

    (for old worker to be released) • activate (start receiving events) • suspend (on page close, but still receive events)
  17. Registering Service Worker

  18. #dfua Registering Service Worker navigator.serviceWorker.getRegistration() .then(function(registration) { if (!registration) {

    navigator.serviceWorker.register('/service-worker.js') .then(function (registration) { console.log('SW registration successful'); }) .catch(function (err) { console.log('SW Registration failed: ', err); }); } });
  19. #dfua Registering Service Worker - Gotchas • navigator.serviceWorker - a

    place for SW API • SW is a separate file • SW can’t be registered from other domain • https is required, but localhost is white-listed • SW doesn’t have access to main app context • in real world we need to check if SW is supported: if ('serviceWorker' in navigator)
  20. Service Worker Typical Scenarios

  21. Installing The App

  22. #dfua self.addEventListener('install', function(event) { var urlsToCache = ['/', '/app.css', '/app.js',

    '/vendor.js']; event.waitUntil( caches.open('static-cache-v1').then(function(cache) { return Promise.all(urlsToCache.map(function (url) { return cache.add(url); })); }); ); }); Installing The App
  23. #dfua • ExtendableEvent - API allowing to pause event processing

    • window.caches - place for Cache API Installing The App - Gotchas
  24. Cache First Caching Strategy

  25. #dfua Cache First Caching Strategy self.addEventListener('fetch', function(event) { event.respondWith( caches.open('static-cache-v1').then(function(cache)

    { return cache.match(event.request).then(function(cachedResponse) { if (cachedResponse) return cachedResponse; else return fetch(event.request); }); }) ); });
  26. #dfua Cache First Caching Strategy - Gotchas • FetchEvent -

    new type of event that allows to intercept network requests • everything is a Promise when it comes to Service Worker
  27. Network First Cache Strategy

  28. #dfua Network First Cache Strategy event.respondWith( fetch(event.request).then(function (response) { if

    (response.status === 200) { caches.open('api-cache-v1').then(function (cache) { cache.put(event.request, response); }); } return response.clone(); }) ).catch(function (error) { // lookup in cache, if not found - return error(see next slide) });
  29. #dfua Network First Cache Strategy event.respondWith( fetch(event.request).then(function (response) { //

    add to cache and return response (see previous slide) }).catch(function (error) { return caches.open('api-cache-v1').then(function (cache) { return cache.match(event.request).then(function (cachedResponse) { if (cachedResponse) return cachedResponse; else return error; }); }); }) );
  30. #dfua Network First Cache Strategy - Gotchas • Fetch -

    new API for network requests. It is based on Promise. Say “bye-bye” to callback based XHRs. • Fetch promise .catch() is executed when network is unavailable • Response - API for working with network responses • Response has stream nature so it can be read only once. . clone()method is used to overcome this.
  31. Modifying The Response

  32. #dfua Modifying The Response event.respondWith( fetch(event.request).then(function (response) { return response.text().then(function

    (responseText) { return new Response( responseText.replace(/foo/g, 'bar'), {headers: response.headers} ); }); }) );
  33. #dfua Modifying The Response - Gotchas • We can modify

    the response whatever way we want! • We’ve got network interceptors running right in browser!
  34. Updating The App

  35. #dfua Updating The App • Install event is fired with

    every service worker file update • Service Worker file is considered updated when it changes in size • Activate event can be used to clean up the old version stuff • Service Worker has two update modes - cold (default) and hot
  36. #dfua Updating The App - Cold Mode • run install

    step • set service worker to waiting state • release old worker when all the pages with current active worker are closed • run activate step when page with app is opened • take control over the page • ==> it’s like Google Chrome update model!
  37. #dfua Updating The App - Hot Mode self.skipWaiting(); => •

    run install step • run activate step • take control over the page ⇓⇓⇓ Old app controlled by new Service Worker.
  38. #dfua Updating The App Cold mode - to use when:

    • new worker version is not compatible with old app • new app version is not compatible with old one (guarantees that different versions don’t run in different tabs)
  39. #dfua Updating The App Hot mode - to use when

    • old app is compatible with new service worker • new app version is compatible with old one
  40. Updating The App - Realisation

  41. #dfua Updating The App - Cache Versioning var staticVersion =

    1; self.addEventListener('install', function(event) { var urlsToCache = ['/', '/app.css', '/app.js', '/vendor.js']; event.waitUntil( caches.open('static-cache-v' + staticVersion).then(function(cache){ return Promise.all(urlsToCache.map(function (url) { return cache.add(url); })); }); ); });
  42. #dfua Updating The App - Cleaning Old Caches self.addEventListener('activate', function(event)

    { event.waitUntil( caches.keys().then(function(cacheNames) { return Promise.all( cacheNames.map(function(cacheName) { if (cacheName.startsWith('static-cache-v') && !cacheName.endsWith('-v' + staticVersion)) { return caches.delete(cacheName); } }) ); }) ); });
  43. Sending Messages To Client

  44. #dfua Sending Messages To Client - Service Worker Side function

    sendToClients (message) { return self.clients.matchAll({includeUncontrolled: true}) .then(function (clients) { clients.forEach(function (client) { client.postMessage(message); }); }); }
  45. #dfua Sending Messages To Client - Client Side navigator.serviceWorker.addEventListener('message', function(event)

    { // event.data is the message we received console.log(event.data); });
  46. That’s It! We are ready to pack our own apps!

  47. But remember - with big power comes big responsibility!

  48. What about push messages and background sync?

  49. #dfua Push Messages Push messages is a really HUGE topic.

    There is a great article on Google Dev Site: And nice simple demo:
  50. #dfua Background Sync • Gives the ability to postpone tasks

    until user has connectivity • Now in state of proposal draft, available only in Chrome Canary, and a big subject to change. • Docs available here:
  51. Browser Support

  52. #dfua Service Worker Browser Support Chrome - very good (most

    features) Firefox - quite good (key features, many features in nightly) Opera - good (key features) IE - optimistic (no support, but under consideration) Safari - bad (no public commitment) Details:
  53. Resources

  54. #dfua Resources • Developer Guide on Chromium site: https://www.chromium.org/blink/serviceworker •

    Is Service Worker Ready? by Jake Archibald: https://jakearchibald.github.io/isserviceworkerready/ • Introduction To Service Worker on HTML5 Rocks : http://www.html5rocks.com/en/tutorials/service-worker/introduction/ • Service Worker Libraries maintained by Google: https://developers.google.com/web/tools/service-worker-libraries/
  55. Now go, grab latest Chrome and try it!

  56. Thank you! Questions? Questions? https://facebook.com/viktor.zu https://www.linkedin.com/in/zozulyakviktor http://last.fm/user/zuzya