title: Service Worker author: name: I'm Adrien, frontend developer url: https://oodrive.com email: [email protected] theme: ./theme controls: true output: index.html
--
--
--
sequenceDiagram
participant B as π Browser
participant X
B->X: HTTP requests, compute, DOM changes ...
--
sequenceDiagram
participant B as π Browser
participant W as π Worker
B->>W: create
--
sequenceDiagram
participant B as π Browser
participant W as π Worker
B->>W: create
loop events
W--xB: message
B--xW:
end
--
All run background scripts independently of any UI
- Web Workers since 2010, perform heavy computation, ex: pdfjs
- Shared Workers since 2010, shared across same origin
webkit in 2015 - Service Workers since 2014, control HTTP requests from same origin
--
--
A service worker acts as a proxy between the browser (your web application) and the network
Main usages
- Offline access
graph LR
B("π") --> S("π")
S -.- N("β")
style B fill:none,stroke:none
style S fill:none,stroke:none
style N fill:none,stroke:none
- Push notifications
graph RL
N("π¨") --> S("π")
S -.- B("π")
style B fill:none,stroke:none
style S fill:none,stroke:none
style N fill:none,stroke:none
--
support: chrome, mozilla, android, opera, edge, safari
- Promises construction to execute code after a task is fulfilled
- postMessage method to communicate between contexts
- fetch function to make simple HTTP requests, successor of XHR
--
support: chrome, mozilla, android, opera, edge (development), safari (development)
- HTTPS only, same origin for security reason
- No DOM access no
document
, norwindow
- Behind flag in Edge & Safari Technical Preview
--
--
support: chrome, mozilla, android, opera, edge (development), safari (development)
main.js
if (navigator.serviceWorker)
navigator.serviceWorker
.register('/service-worker.js', { scope: '/' })
.then(registration => registration.state)
Multiple Service Workers must register distinct scopes
--
support: chrome, mozilla, android, opera, edge (development), safari (development)
service-worker.js
self.addEventListener('install', event =>
event.waitUntil(/* ready to activate */)
)
graph LR
P["π page"] -. register .-> I("β install")
I --> A("β activate")
I --> E("β error")
style P fill:white
style I fill:white,stroke:#41b6e8
style A fill:white,stroke:green
style E fill:white,stroke:red
--
support: chrome, mozilla, android, opera, edge (development), safari (development)
- Activates only inside scope
- Skip the
install
event handler
graph LR
P["π page"] -. in scope .-> A("β activate")
A -. control .-> P
click P callback "in the Service Worker Scope"
style P fill:white,stroke:lightgrey
style A fill:white,stroke:green
π Service Worker: An Introduction
--
support: chrome, mozilla, android, opera, edge (development), safari (development)
New Service Worker will wait deactivation of the old one before it activates
graph LR
subgraph Old Service Worker
O("β activate") --> D("β deactivate")
end
subgraph New Service Worker
O("β activate") -. updatefound .-> I("β install")
I -. waiting .-> A("β activate")
end
style O fill:white,stroke:lightgrey
style D fill:white,stroke:red
style I fill:white,stroke:#41b6e8
style A fill:white,stroke:green
--
Main functional events
- fetch intercepted an HTTP request (made by main thread)
- message received a message via postMessage
- push received a push notification
--
graph LR
A("β Activated") --> D{"β Idle"}
D --> F("β Handle event")
F --> D
D --> T["β Terminated"]
T --> F
style A fill:white,stroke:green
style D fill:white
style F fill:white,stroke:#41b6e8
style T fill:white,stroke:red
Service worker may terminate at any time!
--
--
You cannot rely on global state within a service worker
- No Local Storage
- But IndexedDB (use a wrapper!)
- Use the Cache interface
--
- Beware of redirects, credentials, streams
- Avoid puting version in script URL
- Specific debug tools chrome://serviceworker-internals
- By default first run does not
control
the main Thread
--
--
support: chrome, mozilla, android, opera, edge (development), safari (development)
service-worker.js
const CACHE = 'my-awsome-pwa',
const FILES = ['/', '/styles.css', '/script.js']
self.addEventListener('install', event =>
event.waitUntil(
caches.open(CACHE)
.then(cache => cache.addAll(FILES))
)
)
π Service Worker specification
--
support: chrome, mozilla, android, opera, edge (development), safari (development)
service-worker.js
self.addEventListener('fetch', event =>
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
)
)
--
- Cache only KISS Progressive Web Application
- Cache first, falling back to network static assets
- Network first, falling back to cache API resources
- etc
--
--
- Used to be complex vendor specific implementations
- Fully standardized browser provides push server
- Native notifications UI with user permission
π¨ Push Notifications in Web App
--
support: chrome, mozilla, android, opera, edge (development), safari (development)
main.js
const registration = await navigator.serviceWorker.ready
const push = await registration.pushManager.subscribe()
sendToBackend(push.endpoint)
manifest.json
(chrome only)
{ ..., "gcm_sender_id": "<Your Sender ID Here>" }
--
- Background sync wait for stable network connection (backoff)
- Periodic background sync scheduled synch (in design)
- Background fetch HTTP request outlives browser close
πΆ Background-fetching proposal
--
- Written in Markdown with Cleaver
- Graphs with Mermaid, code with Highlights
- Theme Select, icons UTF8 with Symbola font
- Jake Archibald, author/advocate of specs
- Google developers website & MDN
- w3c & whatwg
--
--
sequenceDiagram
participant B as π Browser
participant W as π Service Worker
participant S as β‘ Push Server
B->>W: register
activate B
activate W
W--xB: message
deactivate W
B--xW: fetch
activate W
deactivate W
deactivate B
S--xW: notification
activate W
W--xB:
deactivate W
--