Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 26, 2022 12:19 am GMT

Service workers tutorial

Web developers oranyone involved inweb development can tell you they know ofworkers inbrowsers. However, the problem isthat most folks think ofeither web workers ingeneral, orservice workers (oreven shared workers) when they say workers. These terms can beconfusing, especially ifyou didnt come across them.

That iswhy today, wewill dive into service workers. Well see why youd want touse service workers, what they are, how they work and explain the difference between service workers and other workers inthe browser.

Before westart, lets dive inand see what the web workers are ingeneral.

What are web workers?

Aweb worker isabackground task defined via script aJavaScript file. Web workers can communicate back and forth with their creator. Aweb worker runs inaseparate thread from the main JavaScript thread. Tosee how they work and get asmall introduction tothe world ofweb workers, letus gothrough asimple example.

You can create aweb worker inthe application code likeso:

const myAwesomeWorker = new Worker('/path/to/worker.js');

Then, you can communicate with the worker:

myAwesomeWorker.postMessage('Hi there, love you');

Inside the web worker, you can accept the message and respond back tothe caller:

// /path/to/worker.jsonmessage = function (e) {  // do some magic here  postMessage('I am all done, back to you, main application code.');};

Then, the caller can listen tothe messages from the web worker:

myAwesomeWorker.onmessage = function (e) {  console.log('Message received from myAwesomeWorker');  console.log(e.data);};

Above isatrivial example ofhow web workers work, but itshould beagreat start toour topic where wewill explore aspecialized worker service worker. Tosummarize, aweb worker isaJavaScript file that runs inadifferent thread, but still can communicate with our application code. Wecan communicate with the web worker back and forth, and itcan beagreat helper when wewant todelegate work away from the main thread ofour application.

Now that wegot over the basics, lets see what service workers are.

What are service workers?

Aservice worker isamediator between the web application, the browser, and the network. The service worker islike aproxy server that sits between your application and the network, intercepting requests and serving the corresponding responses.

You can also envision aservice worker asamiddleware for your site. Any request from the site and any response itgets goes through the service worker. Besides being amiddleware, service workers also have access toacache, where they can save responses and assets.

All this makes aperfect scenario ifyoure planning toadd exceptional offline support toyour website. Aservice worker can decide ifitshould serve aresource from the cache orthe network, asitwould happen without aservice worker. However, itisimportant tonote that not all browsers support service workers. Weshould make service workers anenhancement rather than arequirement for our website.

One more use case can bethe ability touse Push API toreceive notifications from the server. This API provides the option for developers todeliver asynchronous messages and updates tousers who optin, resulting inbetter engagement with timely new content. For example, you can build aservice worker that will update users when anew app isavailable.

OK, now that weunderstand the concept ofservice workers, lets see what atypical lifecycle ofaservice workeris.

The service worker lifecycle

Tofully understand how service workers behave, wemust understand the different states they can existin. Touse aservice worker, wehave toregister itonthe client side. Heres how wecan doit:

if ('serviceWorker' in navigator) {  navigator.serviceWorker.register('/myServiceWorker.js');}

First, wedoasimple check tosee ifservice workers are supported inthe users browser. Then, wecall navigator.serviceWorker.register with the path toour service worker JavaScript file.

Then, wehave todistinguish two use cases:

  1. When weregister aservice worker for the first time
  2. When weupdate the existing service worker

1. Registering aservice worker for the first time

Inthe first scenario, where the page doesnt have any service workers, the client will attempt todownload the service worker weregistered. After the download, the browser will try toinstall the service worker. After successful installation, the service worker isthen activated and ready toperform.

Tosum upthe first case, the lifecycle looks like this:

  1. Download (parse, and execute)
  2. Install
  3. Activate

2. Updating existing service worker

Now, inthe second use case where wewant toupdate the existing service worker, wemight get into anextra state between installing and activating. Ifanexisting service worker isavailable, the installation for the new worker isdone inthe background. Once the installation iscomplete, the new worker isnot yet activated.

The worker now needs towait for when there are nolonger any pages loaded that are still using the old service worker. Assoon asthere are nomore pages tobeloaded, the new service worker activates (becoming the active worker). You can skip the waiting for the new worker using ServiceWorkerGlobalScope.skipWaiting().

Sowhen the service worker isupdated, this ishow its lifecycle looks:

  1. Download
  2. Install
  3. Wait
  4. Activate

Wetalked about how toregister aservice worker, and how browsers later activateit. But how does the lifespan ofaservice worker end?

Its important tonote that service workers dont live indefinitely. While exact timings differ between browsers, service workers will beterminated iftheyve been idle for afew seconds, oriftheyve been busy for too long. Ifaservice worker has been terminated and anevent occurs that may start itup, itwill berestarted.

All inall, the service worker lifecycle can beshown inone diagram:

OK, now that wegot through the basics onhow toregister aservice worker and its whole lifecycle inthe browser, lets goonand see how itworks. Were going tocreate aservice worker that caches our requests.

Using service worker tocache requests

One ofthe most common use cases for service workers isthat they are used tocache assets and requests onyour website. They are afundamental part ifyoure looking into makinga Progressive Web App (PWA). Aswementioned before, when registered, the service worker acts asalayer between your website and the network. The worker intercepts every request from your website out tothe world.

Inaddition tobeing amiddleware between your website and the world, aservice worker can utilize the Cache Storage API. Inthis example, wewill use just that asimple service worker that caches requests inthe browsers cache. This API works similarly tothe browsers standard cache, but itisspecific toyour domain. You have full control over the API, meaning you can control when the keys expire and add new keys. Its important tomention that the service workers storage isindependent ofthe browser HTTP cache toensure wedont mix the two.

Without further ado, letus gointo how wecan cache our resources with service workers.

Caching assets onservice workers installation

Before our service worker isfired, weneed toregister itonapage. Wewill use asimilar code weused inthe lifecycle section:

const registerWorker = async () => {  if ('serviceWorker' in navigator) {    try {      const registration = await navigator.serviceWorker.register('/worker.js');      console.log('Service worker registration succeeded:', registration);    } catch (error) {      console.error(`Registration failed with ${error}`);    }  }};registerWorker();

First, wewill check whether service workers are supported inthe context where our code runs with 'serviceWorker' innavigator check. After that, well do navigator.serviceWorker.register('/worker.js') which will register the worker.js file asour service worker. After that, well write tothe browser console, toensure everything gets set upcorrectly. Ifthere were anerror somewhere, our try/catch block would take care ofthat.

Also, itisgood tonote that every service worker has aconfigurable scope. You can set scope when registering ascript tobeaservice worker likeso:

navigator.serviceWorker.register('worker.js', { scope: '/some-scope' });

Ifyou omit scope, itwill use the default value. The default value ofthe scope depends onwhere the service worker got registered. Ifyou register aservice worker under domain.com/index.html, the worker will control domain.com/index.html and all pages underneath. Ifyou change the scope tosomething else like below:

navigator.serviceWorker.register('worker.js', { scope: '/blog/' });

And, ifyou register the service worker inthe domain.com/index.html, then itwill control only the domain.com/blog/ portion ofit.

Great, now that weregistered our service worker and understand the concept ofaworkers scope letus define some logic inthe service worker file worker.js. Heres how itwill look:

const version = 'v1';const addResourcesToCache = async (resources) => {  const cache = await caches.open(version);  await cache.addAll(resources);};self.addEventListener('install', (event) => {  console.log(`${version} installing...`);  event.waitUntil(    addResourcesToCache([      '/',      '/index.html',      '/styles.css',      '/script.js',      '/jungle.png',    ])  );});

Atthe top, wefirst declare the version tobe v1 well get tothis inasecond. Then, wedefine the addResourcesToCache function that opens aCache Storage instance and writes toitwith:

const cache = await caches.open(version);await cache.addAll(resources);

The caches.open receives astring that represents acache name. Lateron, aswechange our service worker, wewill have tochange the name ofthe cache and remove the old one, but well get tothat inasecond.

Soifweopen our page now, the service worker defined in worker.js will install and cache our resources. Tobesure ithappened, wecan check the Applications tab inGoogle Chrome. Ifweopen the Storage section there, wewill see how much storage our website istaking:

Also, wecan gointo Cache Storage and check the v1 cache wejust created inour service worker. InCache Storage, you should see the resources wespecified:

Cool, wegot our websites assets inthe service worker cache, safely away from the standard browser cache. But, what now, you must beasking? Now, weneed totell the browser toserve those assets from the cache. And agreat way todothat istouse our service worker.

Serving assets from the cache

Wewill listen for a fetch event inour worker, and intercept requests going from our website tothe network. Heres how itlooks:

self.addEventListener('fetch', (event) => {  event.respondWith(caches.match(event.request));});

With this code, weare hijacking each request firing from our site. Then, wecall respondWith and respond with acached value inour cache. Ifweadd this code, close and then reopen our website, and open the Network tab inabrowser. Wewill see that the resources are cached inbythe service worker:

This isall fine and dandy, but ifweadd aresource toour site orremove aresource from the cache manually, our site can break.

For example, Itried toremove styles.css from the cache inApplication Cache Storage, and the CSS went missing the next timeI opened the page. Neither worker nor the browser fetched styles.css again because ofthe logic inthe worker. Tomitigate this, wehave tomake sure that arequest gets passed through our service worker iftheres nomatching resource inour cache. Heres how wecan dothat:

const cacheFirst = async (request) => {  const responseFromCache = await caches.match(request);  if (responseFromCache) {    return responseFromCache;  }  return fetch(request);};self.addEventListener('fetch', (event) => {  event.respondWith(cacheFirst(event.request));});

With the new cacheFirst function, weare sure that arequest that isnot inthe cache will get sent out tothe network with fetch(request).

Wecan goastep further, and cache requests that are not inthe cache. That way, wewill fetch aresource from the network, and store itinto the cache. Ifour app goes offline for some reason, that resource will still beavailable, yay! This iswhat our fetch event handler should look like:

const putInCache = async (request, response) => {  const cache = await caches.open(version);  if (request.method !== 'GET') {    console.log('Cannot cache non-GET requests');    return;  }  await cache.put(request, response);};const cacheFirst = async (request) => {  const responseFromCache = await caches.match(request);  if (responseFromCache) {    return responseFromCache;  }  const responseFromNetwork = await fetch(request);  // we need to clone the response because the response stream can only be read once  putInCache(request, responseFromNetwork.clone());  return responseFromNetwork;};self.addEventListener('fetch', (event) => {  event.respondWith(cacheFirst(event.request));});

Here, wedefine the putInCache function that puts the request and its response into the cache.

Ifyou notice, wealso check for arequest method. Bydesign, wecannot cache non-GET requests inthe Cache Storage API. After that, wechanged the cacheFirst function tocall the putInCache function with the request object and the clone ofaresponse. Wehave toclone the response, because request and response streams can only beread once. Then, wereturn the original response tothe browser.

And that isit, this isthe basic service worker that will cache all GET requests that gofrom your website tothe network. This setup can beagreat first step ifyou plan tomake your app work offline. You can play around with different caching strategies, lets quickly goover them.

Cache-First

Weimplemented here acache-first approach, where wefirst try toserve arequest from the cache ifitisavailable.

Network-First

You can try and implement anetwork-first approach, where wenormally send out the request tothe network and cacheit. Then, when the request cant bemade (the site lost connectivity, for example) weserve the failed request from the cache.

Stale-While-Revalidate

Theres also astale-while-revalidate approach that will use acached version ifavailable, but itwill fetch anupdate and put itinthe cache for next time.

Wecould also goonand make sure that auser gets afallback response, incase the resource isnot inthe cache and itcant befetched over the network. But this should beenough toget you started onaservice worker. Instead, Id likeus tocompare the difference between service workers and workers ingeneral. Lets dive into that inthe next section.

Service workers versus other workers

Now that wehave anunderstanding ofservice workers, wecan look over other types ofweb workers, and how they differ from each other. Lets start with how similar web workers and service workers are.

Web workers and service workers are two different types ofbackground scripts available towebsites inthe browser. Both web workers and service workers have some things incommon:

  • They both run inadifferent thread without blocking the main JavaScript thread and the user interface.

  • They cant interact with the DOM directly, and they have limited access tobrowser APIs.

  • They both are web workers. But service workers are just aspecialized version ofweb workers.

And the differences between them:

  • Aswementioned before, service workers allow you tointercept network requests (via the fetch event), and tolisten for Push API events inthe background (via the push event). Web workers cant dothat.

  • Apage can spawn multiple web workers, but only one service worker controls all the active tabs under the scope itwas registered with.

  • The lifespan ofthe web worker istightly coupled tothe tab itbelongsto, while the service workers lifecycle isindependent ofit. When you close the tab where aweb worker isrunning, the worker will beterminated. Aservice worker can continue running inthe background, even when the site that registered itdoesnt have any active tabs open.

  • Service workers only run over HTTPS for security reasons. Being able tomodify network requests, they are wide open toman-in-the-middle attacks, which iswhy they are only allowed onsecure connections. InFirefox, Service Worker APIs are also hidden, and cannot beused when the user isinprivate browsing mode. Theres anopen bug for that ifyou want totrackit.

There are also shared workers. They are workers that can beutilized bymultiple scripts running indifferent windows, iframes, and similar, aslong asthey are inthe same domain asthe worker. The scripts must communicate via anactive port, sothey are more complex than the standard workers orservice workers.

Besides these, you can also utilize worklets. Aworklet interface isalightweight version ofweb workers, and gives developers access tolow-level parts ofthe rendering pipeline. Worklets can beused torun JavaScript and WebAssembly code toperform graphics rendering oraudio processing, where high performance isrequired.

Summing up

Phew, what aride. Welearned the basics ofservice workers, but lets goover itonce again. Here are things toremember:

  1. Aservice worker isaspecialized worker that performs away from the main JavaScript thread.
  2. Aservice worker can act asmiddleware between your site and the network.
  3. Tohave aservice worker onyour website, ithas tobefirst downloaded, installed, and then activated.
  4. Ifyoure updating anexisting service worker, the previous service worker must beunloaded from the page (oryou can instead skip waiting for that).
  5. Service workers only run over HTTPS for security reasons.
  6. One ofthe main use cases for aservice worker istocache resources.

Asfar asweb workers are concerned, they are mostly used todelegate work from the main thread while the page isopen. Assoon asthe page isclosed, the classic worker isterminated aswell.

Ifyoure interested inthe code from this blog post, Ipushed ittoa repository onGitHub. You can check itout there, ithas asmall index.html page that showcases how you can cache resources.

Thats all folks, next time, wewill gointo how todebug service workers (even though weshowed aglimpse ofwhere you can dothat), and wecan show how touse service workers insome other use case.

Until then, thanks for reading, and catch you inthe next one.

Originally published by Nikola uza in Uploadcare Blog


Original Link: https://dev.to/uploadcare/service-workers-tutorial-1b7h

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To