Service Workers is a core part of Progressive Web Apps that allows caching of resources and Web push notifications to create a good offline experience. They act as proxies between Web applications, browsers, and the network, allowing developers to intercept and cache network requests and take appropriate actions based on the availability of the network.
A service worker runs on a separate thread, so it is non-blocking. This also means that it does not have access to the DOM and other apis available in the main JavaScript thread, such as cookies, XHR, Web storage apis (local storage and session storage), etc. Because they are designed to be completely asynchronous, they rely heavily on promises to wait for a response from a network request.
For security reasons, Service Workers run only using HTTPS and cannot be used in private browsing mode. However, when making a local request, you don’t need a secure connection (which is enough for testing).
Browser support
Service Workers is a relatively new API that is only supported by modern browsers. Therefore, we first need to check if the browser supports the API:
if('serviceWorker' in navigator) {
/ / Supported 😍
} else {
/ / Not supported 😥
}
Copy the code
The Service Worker registration
Before we can start caching resources or intercepting network requests, we must install the Service worker in the browser. Because a service worker is essentially a JavaScript file, you can register it by specifying the path to the file. This file must be accessible over the network and should contain only the Service worker code.
You should wait for the page loading is completed, then the service worker. The file path to the navigator serviceWorker. The register () method:
window.addEventListener('load', () = > {if ('serviceWorker' in navigator) {
// register service worker
navigator.serviceWorker.register('/sw-worker.js').then(
(a)= > {
console.log('SW registration succesful 😍');
},
err => {
console.error('SW registration failed 😠', err)
});
} else {
/ / Not supported 😥}});Copy the code
The above code can be run every time the page loads without any problems; The browser will decide if the Service worker is installed and handle it accordingly.
Service Worker life cycle
The registration life cycle consists of three steps:
- download
- The installation
- The activation
When users first visit your site, they immediately download the Service worker file and try to install it. If the installation is successful, activate the service worker. None of the functions in the service worker file are available until the user refreshes the current page after visiting another page.
Browser events
Once the service worker is installed and activated, it can start intercepting network requests and caching resources. This can be done by listening for events emitted by the browser in the service worker file. The browser emits the following events:
- installEmitted when the Service Worker program is installed
install
- activateWill be sent after successful registration and installation of the Service Worker program
active
. This event can be used to remove expired cache resources before a new version is installed. - fetchWhenever a web page requests a network resource, it will be issued
fetch
. Resources can be anything: new HTML documents, images, JSON apis, style sheets, or JavaScript files, and anything available at a remote location. - pushWhen you get a new push notification,
push
Sent by the Push API. You can use this event to send messages to usersAccording to notice. - syncWhen the browser detects network availability after a connection has been lost, it drops a link
sync
.
Provide cache resources
We can listen for install events when installing service workers to cache specific resources that need to service web pages when we leave the network:
const CACHE_NAME = 'site-name-cache';
self.addEventListener('install', event => {
event.waitUntil(
caches
.open(CACHE_NAME)
.then(cache= >
cache.addAll([
'favicon.ico'.'projects.json'.'style.css'.'index.js'.'https://fonts.googleapis.com/css?family=Open+Sans:400, 700'))); });Copy the code
In the example above, the code uses the Cache API to store the resource in a Cache named site-name-cache.
The self keyword is a read-only global attribute that service Workers use to access themselves.
Now let’s listen for a FETCH event to check if the requested resource is already stored in the cache and return it if found:
// ...
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response= > {
if (response) {
//found cached resource
return response;
}
returnfetch(event.request); })); });Copy the code
We look for the resource cache entry identified by the request attribute, and if none is found, we send a fetch request. If you also want to cache new requests, you can do this by handling the response to the request and then adding it to the cache, as follows:
// ...
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response= > {
if (response) {
//found cached resource
return response;
}
// get resource and add it to cache
return fetch(event.request)
.then(response= > {
// check if the response is valid
if(! response.ok) {return response;
}
// clone the response
const newResponse = response.clone();
// add it to cache
caches.open(CACHE_NAME)
.then(cache= >
cache.put(event.request, newResponse)
);
// return response
returnresponse; }); })); });Copy the code
The Service Worker update
After the Service Worker program is installed, it continues to run until the user removes or updates it. To update the service worker, all you need to do is upload the new version of the service worker file to the server. When a user visits your site, the browser will automatically detect file changes (even if a single byte change is sufficient) and install the new version.
Just like the first installation, the functionality of the new service worker becomes available only when the user navigates to another page or refreshes the current page.
What we can do is listen for the Activate event and delete the old cached resource. The following code does this by iterating through all caches and removing caches that match the cache name:
// ...
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys= > {
return Promise.all(
keys.map(cache= > {
if (cache === CACHE_NAME) {
returncaches.delete(cache); }})); })); });Copy the code
Above is the introduction of Service workers. If you want to learn more, check out the SerciceWorker Cookbook — here are a series of practical examples of using service workers on modern websites.
Reference and postscript
- Original text: dev. To/attacomsian…
- First article: github.com/reng99/blog…
More content, please poke my blog to understand, can leave a star better 💨