Service Worker
Prathik Shetty
THE WEB IS DEAD. LONG LIVE THE INTERNET
- Wired
HTML5 IS DEAD. LONG LIVE HTML5!
- CNET
Web Server
Web Server
Service Worker
Web Server
Service Worker
Cache
Service Worker
Push
A proxy that sits between web applications, and the browser and network
Works only on
Use Cases
Offline Mode
Push Notification
Background Sync
& More
- Stub servers for testing
- Manipulate responses
- WebApp Update
- Support for a new image format
- Easy Failover support
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js', {
scope: '/app/'
})
.then(function(registration) {
console.log('SW registered');
});
// .catch a registration error
} else {
console.log('SW registered ');
}
index.html
self.addEventListener('install', function(event) {
// On installation
});
self.addEventListener('activate', function(event) {
// on activation
});
sw.js
Installation
Activate
Error
Idle
Fetch/Push
Terminated
No SW
SW Lifecycle
Event Listeners
- Install
- Activate
- Message
Functional Events
- Fetch
- Sync
- Push
- & more
self.addEventListener('fetch', function(event){
event.respondWith(
caches.match(event.request)
);
});
sw.js
self.addEventListener('sync', function(event) {
if (event.tag === 'my-sync-tag') {
event.waitUntil(doSomething());
}
});
sw.js
self.addEventListener('push', function(event) {
event.waitUntil(
self.registration.showNotification('Notification Yay!!!');
);
});
sw.js
Examples
var cacheName = 'cache-v1';
var filesToCache = ['/main.js', '/index.html', '/offline.html', ...];
self.addEventListener('install', event => {
event.waitUntil(
caches
.open(cacheName)
.then(cache => {
return cache.addAll(filesToCache);
})
.then(() => {
return self.skipWaiting();
})
);
});
sw.js
Pre-Cache on Install
var cacheName = 'cache-v1';
var filesToCache = ['/main.js', '/index.html', '/offline.html', ...];
var nonImportantFilesToCache = [...];
self.addEventListener('install', event => {
event.waitUntil(
caches
.open(cacheName)
.then(cache => {
cache.addAll(nonImportantFilesToCache);
return cache.addAll(filesToCache);
})
.then(() => {
return self.skipWaiting();
})
);
});
sw.js
Pre-Cache on Install v2
self.addEventListener('fetch', event => {
event.respondWith(
caches
.match(event.request)
.then(response => {
return response || fetch(event.request);
});
);
});
sw.js
Serve from cache on fetch
self.addEventListener('activate',e => {
e.waitUntil(
caches
.keys()
.then(keyList => {
return Promise.all(keyList.map(key => {
if (oldCacheNames.includes(key)) {
return caches.delete(key);
}
}));
});
);
return self.clients.claim();
});
sw.js
Clear old cache on activate
self.addEventListener('fetch',event => {
event.respondWith(
return fetch(event.request)
.then(response => {
cache.put(event.request,response.clone());
return response;
});
);
});
sw.js
Save to cache on fetch
self.addEventListener('fetch',event => {
event.respondWith(
return fetch(event.request)
.catch(function() {
return caches.match(event.request);
});
);
});
sw.js
Fallback to cache
const maxItems = 35;
caches
.open(cacheName)
.then(function(cache) {
cache
.keys()
.then(function(keys) {
if (keys.length < maxItems) {
cache.put(request, response);
} else {
cache
.delete(keys[0])
.then(function() {
cache.put(request, response);
});
}
});
});
sw.js
Limiting Cache
self.addEventListener('notificationclose', function(event) {
var notification = event.notification;
var primaryKey = notification.data.primaryKey;
console.log('Closed notification: ' + primaryKey);
});
sw.js
Closes Push Notification
self.addEventListener('notificationclick', function(event) {
var notification = event.notification;
var primaryKey = notification.data.primaryKey;
var action = event.action;
if (action === 'action1') {
clients.openWindow('https://decanter.com/action1.html?pk='+ primaryKey);
} else {
clients.openWindow('https://decanter.com/view.html?pk='+ primaryKey);
}
});
sw.js
Clicks Push Notification
self.addEventListener('fetch', event => {
event.respondWith(
caches
.match(event.request)
.then(response => {
return response || fetch(event.request);
})
.catch(function() {
if (event.request.headers.get('Accept').indexOf('text/html') !== -1) {
return caches.match('/offline.html');
}
});
);
});
sw.js
Offline
Support
Basic Support
Debugging
Freshness or Performance
Network First or Cache First
Service Workers replaces AppCache
but it's a sledgehammer to crack a nut
Impact
73/53/100/92
First Render
Repeat View
How to use in Prod
CTRL + C
CTRL + V
<amp-install-serviceworker>
Works great with AMP
References
Service Worker
By Prathik S
Service Worker
- 2,028