A service worker API is relatively new technology, allowing for running a special type of web worker (a JavaScript), that can be installed in the browser and could provide special features to the website like caching data and allowing for offline load.
Service workers are also heavily used in progressive apps since they provide functionalities for caching resources and push notifications.
Before we jump into building an example app, let’s see what are the main service worker properties.
Service worker properties:
– Service workers are plain JavaScript APIs.
– Service workers run on separate thread so they can’t access the elements of the main page like the DOM elements but this is not the intend of how they are used.
– Service workers can listen on an events emitted from the browser and execute an appropriate script. In example a service worker could listen on browser fetch
event and fetch the data or return it from cache.
Service worker lifecycle.
On a first page visit the only thing that happens is that service worker got installed. No code inside the service worker got executed, unless the user hit another page from this website or reloads the current page. Then service worker kicks in and could provide the extra functionality to the site.
Let’s get started by creating a simple web page, that will make an AJAX request to this service: https://www.toni-develops.com/external-files/examples/service-workers/delayed-response.php that will return the current time, and they display it.
The service intentionally delays the response 5 seconds so this way we could observe when we open the page for the first time how the response is delayed, since service worker is installing and don’t have the response cached. Then if we reload the page the service worker will intercept the request and will serve last cached response right away and then will make a request to the service and update the page.
Building a caching layer for the web resources using service worker.
Let’s create the page.
index.html
<html lang="en"> <head> <meta charset="utf-8"> <title>title</title> <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> <link rel="stylesheet" href="style.css"> <script src="script.js"></script> </head> <body> My fancy new site ! <hr> <div id="container"></div> </body> </html>
script.js
if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('./sw.js').then(function(registration) { // Registration was successful console.log('ServiceWorker registration successful with scope: ', registration.scope); }, function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); }); }); } $.ajax({url: "https://www.toni-develops.com/external-files/examples/service-workers/delayed-response.php", success: function(result){ $("#container").html(result); }});
What’s happening here:
– line 1: we check if the browser supports service workers.
– line 2: added event listener, listening for load
event and on load it installs the service worker. The rest is just error handling.
-line15:we make a request to the service using plain jQuery AJAX request.
style.css
body { background: silver }
Now it’s time to write the actual service worker.
sw.js
var CACHE_NAME = 'my-site-cache-v1'; var urlsToCache = [ './index.html', './style.css', './script.js', 'https://www.toni-develops.com/external-files/examples/service-workers/delayed-response.php', 'https://code.jquery.com/jquery-3.3.1.min.js' ]; self.addEventListener('install', event => { // Perform install steps event.waitUntil( caches.open(CACHE_NAME) .then(cache => { console.log('Opened cache'); cache.addAll(urlsToCache); }) ); }); self.addEventListener('fetch', event => { console.log("(9)served from service worker: ",event.request.url); // serve as soon as possible from cache event.respondWith(fromCache(event.request)); // update cache event.waitUntil( update(event.request) ); }); /** * * Helper methods */ function fromCache(request) { return caches.open(CACHE_NAME).then(cache => { return cache.match(request); }); } function update(request) { caches.open(CACHE_NAME).then( cache => { fetch(request).then( response => { cache.put(request, response) }); }); }
What we just did:
– line 1: we specified the cache key (we have to make sure that it is unique)
– line 2: we created an array urlsToCache
having all URLs that we want to cache. If one of the URLs fail, service worker will fail to install so we have to keep this url list short.
– line 11: added event listener, that on install
event (when the service worker is invoked for the first time) will open the cache (line 14), and will add all urls to the cache (line 17) and then return the contents.
– line13: will simply prevent service worker to be killed before finishing with caching the resources.
– line 23: added fetch
event. This will fires wherever a web page request a resource (*.js, *.css, images or in this case AJAX request)
– line 26: will return the asset right away from cache
– line29: will fetch the asset from the ‘slow’ service to update the cache for the next request.
Now let’s look at the helper methods:
–fromCache
function is simply opens the cache and finds the request key.
– update
function is opening the cache, fetches a fresh data from the service (or stores a fresh copy of web resource) and puts it back into the cache using request as a key.
Testing the project.
Open an empty tab in Chrome (comand + T), make sure that the dev tools are also open on the net tab (alt + comand + i), and the console drawer is visible (escape toggles the drawer)
Copy the example URL example found here and paste it into Chrome’s tab.
You will see the message “My fancy new site !” and after around 5 seconds current date and time will appear (- 5 seconds that took for the service to return the data)
Now service worker is installed. Reload the page and you will see that the current time will appear instantly from the cache. Observe the net tab and you will notice that the service worker also made a request to the service to update the data (the one that is pending on the picture below) and also web resources are now coming from the service worker (the size column).
Additionally if you want to clear the cache you could do it by clicking on the Application tab in the dev tools “Clear Storage” and then “clear site data”.