View
288
Download
2
Category
Preview:
DESCRIPTION
Service Workers is coming. Bring your own magic with the first programmable cache in your script, and more! Presented at the GDG Korea DevFest 2014 on the 31st of May 2014: https://sites.google.com/site/gdgdevfestkorea2014/
Citation preview
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
Recommended