Service Worker

Meaning

Service Worker is a Worker thread that runs in the background first, and then it will run for a long time as a service, which is very suitable for functions that do not require web pages or user interaction. Its most common use is to intercept and process network requests.

Service Worker is a script that runs in the background and acts as a proxy server to intercept network requests from users, such as loading scripts and pictures. Service Worker can modify the user's request or send a response directly to the user without contacting the server, which allows the user to use the web application offline. It can also cache resource files locally and load files directly from the cache, thus speeding up access.

if ("serviceWorker" in navigator) {
  window.addEventListener("load", function () {
    navigator.serviceWorker.register("/service-worker.js");
  });
}

After the above code confirms that the browser supports Service Worker, it will register a Service Worker.

In order to save memory, the service worker sleeps when not in use. It also does not save data, so when restarting, in order to get the data, it is best to put the data in IndexedDb.

Service Workers are event-driven.

The following is an example of intercepting a request.

self.addEventListener('fetch', (event) => {
  event.waitUntil (
    if (event.request.url.includes('/product') {
      let productId = event.data.productId
      let productCount = getProductData(productId)
      indexedDB.open('store', 1, (db) => {
        let productStore = db.createObjectStore('products', { keyPath: 'id' })
        productStore.put({ id: productId, count: ++productCount })
      })
    })
  )
})

Service Workers cannot directly manipulate the DOM.

Steps for usage

Registration

The first step in using a service worker is to tell the browser that a service worker script needs to be registered.

navigator.serviceWorker.register('sw.js'.then(() => {
  console.info('Registered successfully')
}).catch((err) => {
  console.error('Registration failed')
})

The sw.js in the above code is the service worker script that requires browser registration. Note that this script must be in the same domain as the current URL, and the service worker does not support cross-and scripting. In addition, sw.js must be loaded from the HTTPS protocol.

By default, Service worker only takes effect on the root directory /. If you want to change the effective range, you can run the following code.

navigator.serviceWorker.register("/service-worker.js", {
  scope: "/products/fashion",
});

Installation

Once the registration is successful, the next step is the work of the service worker script. The following code is written in the service worker script.

After registration, the install event will be triggered. The service worker script needs to listen for this event.

self.addEventListener("install", (event) => {
  event.waitUntil(() => console.info("Installation complete"));
});

The event.waitUntil() method specifies the callback function after the event is completed.

self.addEventListener("install", (event) => {
  let CACHE_NAME = "xyz-cache";
  let urlsToCache = ["/", "/styles/main.css", "/scripts/bundle.js"];
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => cache.addAll(urlsToCache))
  );
});

Activate

After the installation is complete, the service worker will wait for activation.

self.addEventListener("activate", (event) => {
  let cacheWhitelist = ["products-v2"];

  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames.map((cacheName) => {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

Communication between Service Worker and Web Page

self.addEventListener("activate", (event) => {
  event.waitUntil(
    self.clients.matchAll().then((client) => {
      client.postMessage({
        msg: "Hey, from service worker! I'm listening to your fetch requests.",
        source: "service-worker",
      });
    })
  );
});

In the above code, the Service Worker listens to the activate event, and then sends a message to the client.

The client needs to deploy message monitoring code.

this.addEventListener("message", (data) => {
  if (data.source == "service-worker") {
    console.log(data.msg);
  }
});