Service workers
description
Transcript of Service workers
Service WorkersBring your own magic
Jungkee SongGithub: @jungkeesTwitter: @jungkees
Google+: +JungkeeSong
See this slide with animation here!
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.
Installed!Work in progress
Activating!
https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
https://github.com/slightlyoff/ServiceWorker
Work in progress
● 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
Are you online?
Navigation/Resource request
Page
Network fetch
Response
Are you sufficiently online?
Navigation/Resource request
Page
Network fetch
4XX5XX
TimeoutDNS failure
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
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
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
// 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
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");
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
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
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
● 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
● 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
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
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
Updating triggered by● Registration● Automatic by UA● Successful navigation matching● self.update()
Service Worker Lifecycle
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
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
● 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
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?”
References and Practices● Service Worker - first draft published - Jake
Archibald● Specification● Github’s explainer● Github’s implementation considerations