Download - Service workers

Transcript
Page 1: Service workers

Service WorkersBring your own magic

Page 3: Service workers

Service Workers solve ..● Offline usage

○ Offline-first○ Sorry, no magic. Create your own!

■ Programmable cache control■ Custom response - Constructor, IDB, etc.

● Background processing○ Wanna do things while UA’s not running?○ Push messages, Alarms (Task Scheduler),

BackgroundSync, etc.

Page 4: Service workers

Installed!Work in progress

Page 5: Service workers

Activating!

https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html

https://github.com/slightlyoff/ServiceWorker

Work in progress

Page 6: Service workers

● Lifecycle events

Principles and Terms● Runs on same origin● Registration keyed by URL scope● Document is controlled by matching SW

upon navigation● Successfully installed worker is considered

worker in waiting

● Functional events

Page 7: Service workers

Are you online?

Navigation/Resource request

Page

Network fetch

Response

Page 8: Service workers

Are you sufficiently online?

Navigation/Resource request

Page

Network fetch

4XX5XX

TimeoutDNS failure

Page 9: Service workers

fetch event

Have a Service Worker?

Navigation/Resource request

onfetch

Page

SW

Cache self.caches.match(url)

Promise<response>

e.respondWith(Promise<response>)

IDB

new Response({ status: 200, body: { … }})

Offline-first

Page 10: Service workers

fetch event

Now fallback to network with SW

Navigation/Resource request

onfetch

Page

SW

Cache

self.fetch(request)

self.caches.match(url)

Promise rejects

e.respondWith(Promise<response>)

Offline-first

Page 11: Service workers

fetch event

Event-driven worker

Navigation/Resource request

onfetch

Page

SW

Cache self.caches.match(url)

Promise<response>

e.respondWith(Promise<response>)

Page Page

Navigation/Resource request

fetch event

e.respondWith(Promise<response>)

Key concept

Page 12: Service workers

// scope defaults to "/*" navigator.serviceWorker.register("/assets/v1/serviceworker.js").then( function(serviceWorker) { console.log("success!"); serviceWorker.postMessage("Howdy from your installing page."); // To use the serviceWorker immediately, you might call // window.location.reload() }, function(why) { console.error("Installing the worker failed!", why); });

Registration● In the page

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

[ Registration map ]Scope Script URL

Service Worker Lifecycle

Page 13: Service workers

Registration● In the page

navigator.serviceWorker.register("/sw.js");

“/*” /sw.js

[ Registration map ]Scope Script URL

“/foo/*” /foo/sw.js

“/*” /bar/sw.js

Service Worker Lifecycle

navigator.serviceWorker.register("/foo/sw.js", { scope: “/foo/*” });

navigator.serviceWorker.register("/bar/sw.js");

Page 14: Service workers

Installation● Registration triggers installation of the SW● UA fires install event to the installing

Service Worker● The event handler may extend the lifetime

of SW for preparing its caches

Service Worker Lifecycle

Page 15: Service workers

Installation: oninstall● In the Service Worker context

// caching.jsthis.addEventListener("install", function(e) { // Create a cache of resources. Begins the process of fetching them. var shellResources = new Cache();

// The coast is only clear when all the resources are ready. e.waitUntil(shellResources.add( "/app.html", "/assets/v1/base.css", "/assets/v1/app.js", "/assets/v1/logo.png", "/assets/v1/intro_video.webm", ));

// Add Cache to the global so it can be used later during onfetch self.caches.set("shell-v1", shellResources);});

Service Worker Lifecycle

Page 16: Service workers

Programmable cache control● new Cache()

[Constructor]interface Cache { Promise<AbstractResponse> match((Request or ScalarValueString) request, optional QueryParams params);

Promise<sequence<AbstractResponse>> matchAll((Request or ScalarValueString) request, optional QueryParams params);

Promise<any> add((Request or ScalarValueString)... requests); Promise<any> put((Request or ScalarValueString) request, AbstractResponse response); Promise<any> delete((Request or ScalarValueString) request, optional QueryParams params); Promise<any> each(CacheIterationCallback callback, optional object thisArg);};

Service Worker Lifecycle

Page 17: Service workers

● Worker in waiting○ Once self.oninstall() ends○ So to speak, the installation successfully done○ This is not yet controlling the documents in scope

● navigator.serviceWorker.controller○ When all the active documents in scope unload○ The worker in waiting becomes active worker○ self.clients.reloadAll() works○ event.replace() works

Have a controller yet?Service Worker Lifecycle

Page 18: Service workers

● In the Service Worker contextthis.addEventListener("fetch", function(e) { // No "onfetch" events are dispatched to the ServiceWorker until it // successfully installs.

// All operations on caches are async, including matching URLs, so we use // Promises heavily. e.respondWith() even takes Promises to enable this: e.respondWith( caches.match(e.request).catch(function() { return e.default(); }).catch(function() { return caches.match("/fallback.html"); }) );});

Handle a fetch: onfetchFunctional event processing

Page 19: Service workers

Fetch: navigation request

onfetch

sw.js

Cache self.caches.match(url)

Promise<response>

e.respondWith(Promise<response>)

“/*” /sw.js

[ Registration map ]Scope Script URL

“/foo/*” /foo/sw.js

Page Hit “https://example.com/index.html

fetch event

Scope matching

Run SW

Functional event processing

Page 20: Service workers

Fetch: subresource request

onfetch

sw.js

Cache self.caches.match(url)

Promise<response>

e.respondWith(Promise<response>)

“/*” /sw.js

[ Registration map ]Scope Script URL

“/foo/*” /foo/sw.js

Page

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

fetch event

Control

Run SW

Functional event processing

Page 21: Service workers

Updating triggered by● Registration● Automatic by UA● Successful navigation matching● self.update()

Service Worker Lifecycle

Page 22: Service workers

Updating

onfetch

sw-v2

Cache self.caches.match(url)

Promise<response>

e.respondWith(Promise<response>)

“/*” /sw-v1

[ Registration map ]Scope active

fetch event

-

waiting

Page

sw-v1

_Update

_Install

Page

sw-v1 /sw-v2 /sw-v2-

Page

sw-v2

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

Run SW

Service Worker Lifecycle

Page 23: Service workers

Security● Origin relativity● Cross origin resource● HTTPS-only?

○ Protect end users from man-in-the-middle attacks○ Existing "playground" services (e.g. github.io) now

work with HTTPS○ HTTPS is coming across much more of the web

quickly○ Devtools can loosen the restriction for development

Page 24: Service workers

● Event-driven workers○ Free to shutdown the worker when handler’s done○ “Write your workers as though they will die after

every request”● Keep the onactivate short● Platform considerations

○ Enhance matching navigation○ Events implicitly filter○ Enhance startup

Performance

Page 25: Service workers

Is it ready for you?● Chrome Canary

○ Partial under flag○ chrome://flags/#enable-service-worker

● Firefox Nightly○ Partial under flag○ about:config > dom.serviceWorkers.enabled

● Stay alerted!○ Jake’s “Is ServiceWorker ready?”


Top Related