Google documentation says about service workers:

“Rich offline experiences, periodic background syncs, push notifications—functionality that would normally require a native application—are coming to the web. Service workers provide the technical foundation that all these features rely on.”

Service worker is like any other worker which can run in background and can do multiple tasks which you cannot expect from browsers in normal cases. Service workers have been built to be fully async. Service worker can run independently of web pages and they have access to domain-wide events such as network fetches, they have ability to cache resources, they have the ability to respond to network requests, combining this all this provides a way for applications to “go offline”. Service workers could also replace the HTML5 Application Cache in future. Yes, service workers are HTTPS-only.

It is easy to set an app up to use cached assets first with with Service worker, even before getting data from the network. This offline functionality is already available with native apps, which is one of the main reasons native apps are often chosen over web apps. this is where service workers comes to rescue and fix these issues nicely for web applications. that’s why Native Apps are Doomed :)

Sounds good, So question is service workers are supported across all browsers?

First draft of service worker was published on 08 May 2014, from that days support across the browsers has increased, at the moment major browsers such Chrome, Firefox, Opera are supporting the almost all majors APIs and it is also under discussion as part of Safari five year plan. You can see complete compatibility status for different browsers here.

Let’s start with installing a service worker. following code will register the service worker on web page, after service worker is registered we can run tasks using worker. serviceWorker.js should be in root of application.

Register service worker (function () { if ("serviceWorker" in navigator) { navigator.serviceWorker.register('serviceWorker.js', { scope: "./" }) //setting scope of sw .then(function(registration) { console.info('Service worker is registered!'); }) .catch(function(error) { console.error('Service worker failed ', error); }); } })(); 1 2 3 4 5 6 7 8 9 10 11 ( function ( ) { if ( "serviceWorker" in navigator ) { navigator . serviceWorker . register ( 'serviceWorker.js' , { scope : "./" } ) //setting scope of sw . then ( function ( registration ) { console . info ( 'Service worker is registered!' ) ; } ) . catch ( function ( error ) { console . error ( 'Service worker failed ' , error ) ; } ) ; } } ) ( ) ;

inside serviceWorker.js we have install event which will be fired when service worker is installing itself. we attached the callback with install to cache the files array. It will return a promise which will resolve to when installed successfully.

cache the files let cacheName = 'res-1.0'; let files = [ 'js/bootstrap.min.js', 'js/libraries.js', 'css/bootstrap.min.css', 'img/ajax-loader.gif', 'img/dot.gif' ]; self.addEventListener('install', (event) => { event.waitUntil( caches.open(self.cacheName) .then((cache) => { return cache.addAll(files) .then(() => { console.info('All files are cached'); return self.skipWaiting(); //To forces the waiting service worker to become the active service worker }) .catch((error) => { console.error('Failed to cache', error); }); }) ); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 let cacheName = 'res-1.0' ; let files = [ 'js/bootstrap.min.js' , 'js/libraries.js' , 'css/bootstrap.min.css' , 'img/ajax-loader.gif' , 'img/dot.gif' ] ; self . addEventListener ( 'install' , ( event ) = > { event . waitUntil ( caches . open ( self . cacheName ) . then ( ( cache ) = > { return cache . addAll ( files ) . then ( ( ) = > { console . info ( 'All files are cached' ) ; return self . skipWaiting ( ) ; //To forces the waiting service worker to become the active service worker } ) . catch ( ( error ) = > { console . error ( 'Failed to cache' , error ) ; } ) ; } ) ) ; } ) ;

We also have fetch event when some resources fetched over the network. following code first will check if file present in cache and return it, otherwise fetch it from network.

fetch resources self.addEventListener('fetch', (event)=> { event.respondWith( caches.match(event.request).then((response) => { if (response) { return response; // return from cache } // fetch from network return fetch(event.request).then((response) => { return response; }).catch((error) => { console.error('Fetching failed:', error); throw error; }); }); ); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 self . addEventListener ( 'fetch' , ( event ) = > { event . respondWith ( caches . match ( event . request ) . then ( ( response ) = > { if ( response ) { return response ; // return from cache } // fetch from network return fetch ( event . request ) . then ( ( response ) = > { return response ; } ) . catch ( ( error ) = > { console . error ( 'Fetching failed:' , error ) ; throw error ; } ) ; } ) ; ) ; } ) ;

Now open your web page in chrome, at the moment chrome developer tools is ideal for debugging the service workers. under application tab select service worker. you’ll see service worker running.

Under cache > Cache storage you can see the your cached resources. you can change the cache version in serviceWorker to forcefully expire the old cache resources.

serviceWorker.js file



So this is the basic example of service worker register, cache resources and serve from cache. in my next post I’ll go through the implementation of web push notification in browser using Firebase Cloud Messaging (FCM).