Service Worker - Reliability bits

49
Service Worker Reliability bits

Transcript of Service Worker - Reliability bits

Service Worker

Reliability bits

Jungkee SongSenior engineer at Samsung

Web standards authorChromium contributor

Email: [email protected]: @jungkees

Samsung Internet

4.0 shipped SW!

Service Worker

Reliability

Progressive Web Apps

Progressive Web Apps

• Reliability − Fast loading, works on flaky networks

• First-class − Do what native does, background

• Engaging − Home screen access, push notification

Progressive Web Apps

Service Worker

What to solve

Problems

Problems

Not only

But ..

Problems

• Background service − Was not possible without a page

The Total Game Changer!

https://youtu.be/QiXLaisCq10

Udacity Offline-First Web Applications Trailer

Service Worker

Concepts

What to solve

Your programable proxy

Page

Browser

Service Worker

Cache

Net loader and H

TTP cache

Service Worker

Concept

Script runs in the background

A type of web worker

var worker = new Worker(‘dedicated_worker.js');

var worker = new SharedWorker(‘shared_worker.js’);

navigator.serviceWorker.register(“/service_worker.js");

Service Worker

Event-driven

Responds to events

fetch event

Navigation/Resource request

onfetch

Page

SW

Cache Attempt to match cache

Matched Response

Respond to client

Page Page

Event-based worker

Service Worker

Power matters

Intentionally short lifetime

Bound to pagePage

Workernew Worker(‘job.js’)

Run job.js

t

Dedicated worker

* Lifetime is bound to the page unless .terminate is called.

Event-drivenPage

SWfetch event

e.g.<img src=‘pic.png’>

Run sw.js

Browser internal

t

Service worker

Term

inate

Start

onfetch e.waitUntil

push eventStart

Term

inate

onpush e.waitUntil

Registration and SW

registration active worker waiting worker installing worker

ServiceWorkerRegistration

activeactive

installing

Persistent

Client scope

fetch install

registration.active

BrowserInternals

ScriptSurface

registration.active

registration.installing

ServiceWorkerRegistration

ServiceWorker

ServiceWorker

ServiceWorker

Page Page

Service Worker

Make it secure

HTTPS

HTTPS• SW allows powerful stuffs

− Intercept requests and fabricate your

own responses

• Need to guarantee it has not been tempered

during its own fetch

− localhost is allowed during development

− HTTPS setup is needed to deploy

Service Worker

Get it ready

Install and Update

and every navigation and functional event

Installvar navigator.serviceWorker; sw.register(scriptURL, { scope: scopeURL });

Pre-cache resourcesoninstall = e => { /* pre-cache here */ };

Handle fetch eventonfetch = e => { /* respond with magic */ };

Manage Cacheonactivate = e => { /* Deleting cache is on you */ };

Updateregistration.update();

“/assets/v1” /assets/v1/serviceworker.js

[ Registration map ]Scope Script URL

Register

From page// scope defaults to "/" var sw = navigator.serviceWorker; sw.register("/assets/v1/serviceworker.js") .then(reg => { console.log("success!"); reg.installing.postMessage("Howdy from your installing page."); }) .catch(e => { console.error("Installing the worker failed!:", e); });

“/bar” /bar/sw1.js

[ Registration map ]Scope Script URL

“/foo” /foo/sw.js

Register – Multiple registrations

From�page

var sw = navigator.serviceWorker;

① sw.register('/bar/sw1.js', { scope: '/bar' });

② sw.register('/foo/sw.js', { scope: '/foo' });

③ sw.register('/bar/sw2.js', { scope: '/bar' } );

“/bar” /bar/sw2.js

onactivateSW

oninstall

onfetch

Browser internals

oninstall = e => { // pre-cache, etc.};

onactivate = e => { // upgrade Cache, etc.};

onfetch = e => { // Not yet ready};

Fetched sw script

Fetch sw script

Update① ③ Install④ Activate

onfetch

onfetch = e => { // Not yet ready};

Install process triggered by registerEvaluate②

installinginstalledactivated

Service Worker

How interception work

Client matching &

Subresource request

onfetchsw.js

Cache Attempt to match cache

Matched response

Respond to client

“/” /sw.js

[ Registration map ]Scope Script URL

“/foo” /foo/sw.js

Page Navigate https://example.com/index.html

fetch event

Scope matching

Run SW

Client matching (navigation)

onfetchsw.js

CacheAttempt to match cache

Matched response

Respond to client

“/” /sw.js

[ Registration map ]Scope Script URL

“/img” /img/sw.js

Page

Fetch “https://example.com/img/flower.png

fetch event

Control

Run SW

Subresource request

Service Worker

How to handle fetch

Patterns

Cache of static resources in oninstall

https://jakearchibald.com/2014/offline-cookbook/#on-install-as-a-dependencyself.addEventListener('install', function(event) { event.waitUntil( caches.open('mysite-static-v3').then(function(cache) { return cache.addAll([ '/css/whatever-v3.css', '/css/imgs/sprites-v6.png', '/css/fonts/whatever-v8.woff', '/js/all-min-v4.js' // etc ]); }) ); });

Cache on user demand

document.querySelector('.cache-article').addEventListener('click', function(event) { event.preventDefault();

var id = this.dataset.articleId; caches.open('mysite-article-' + id).then(function(cache) { fetch('/get-article-urls?id=' + id).then(function(response) { // /get-article-urls returns a JSON-encoded array of // resource URLs that a given article depends on return response.json(); }).then(function(urls) { cache.addAll(urls); }); }); });

https://jakearchibald.com/2014/offline-cookbook/#on-user-interaction

Cache of dynamic resource

https://jakearchibald.com/2014/offline-cookbook/#on-network-responseself.addEventListener('fetch', function(event) { event.respondWith( caches.open('mysite-dynamic').then(function(cache) { return cache.match(event.request).then(function (response) { return response || fetch(event.request).then(function(response) { cache.put(event.request, response.clone()); return response; }); }); }) ); });

Cache migration in onactivate

https://jakearchibald.com/2014/offline-cookbook/#on-activateself.addEventListener('activate', function(event) { event.waitUntil( caches.keys().then(function(cacheNames) { return Promise.all( cacheNames.filter(function(cacheName) { // Return true if you want to remove this cache, // but remember that caches are shared across // the whole origin }).map(function(cacheName) { return caches.delete(cacheName); }) ); }) ); });

onpushhttps://jakearchibald.com/2014/offline-cookbook/#on-push-message

self.addEventListener('push', function(event) { if (event.data.text() == 'new-email') { event.waitUntil( caches.open('mysite-dynamic').then(function(cache) { return fetch('/inbox.json').then(function(response) { cache.put('/inbox.json', response.clone()); return response.json(); }); }).then(function(emails) { registration.showNotification("New email", { body: "From " + emails[0].from.name tag: "new-email" }); }) ); } });

self.addEventListener('notificationclick', function(event) { if (event.notification.tag == 'new-email') { // Assume that all of the resources needed to render // /inbox/ have previously been cached, e.g. as part // of the install handler. clients.openWindow(‘/inbox/'); } });

Offline Cookbook

https://jakearchibald.com/2014/offline-cookbook/

Application Shell

• Minimal HTML, CSS, and JavaScript powering UI

• Should

− Load fast

− Be cached

− Dynamically display content

https://developers.google.com/web/updates/2015/11/app-shell

Service Worker

Yeah, it works!

Demo

http://stories.flipkart.com/introducing-flipkart-lite/

Service Worker

Yeah, we want more!

Status

Standards

Implementation

4th WD in June 2105

Plan a CR in the 3Q of this year

4.0 40+ 44 32+

Service Worker

And.. Your turn!

In the wild

https://pwa.rocks/

Service Worker

V2 stuffs

Future

V2 features

• Foreign fetch• Cache transaction• Declarative register