define

Service Workers essentially act as proxy servers between Web applications, browsers, and the network (when available). This API is designed to create an effective offline experience that intercepts network requests and takes appropriate action to update resources from the server based on whether the network is available. It also provides a portal to push notifications and access background synchronization apis.

features
  1. An independentworkerThreads, separate from the current web process, have their own separate workerContext.
  2. Once they areinstall, will always exist unless manuallyunregister
  3. You can use it directlyWake up theWhen not in useAutomatic sleep
  4. Programmable interception of proxy requests and returns, cache files, cached files can be retrieved by web processes (including network offline state)
  5. Offline content developers can control
  6. To the clientpushThe message
  7. Cannot operate directlyDOM
  8. Must be inHTTPSorlocalhostWork in the environment
  9. Asynchronous implementation, mostly through internalPromiseimplementation
The life cycle
Definition: Simply put, there are three stages: “Registration (register) “, “Install (Install”, “Activate”, and the most important interception event.fetch”

// main.js
/** ** special note *@scope Represents the URL that defines the scope of service worker registration; The range of urls that the service worker can control */
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('sw.js', {scope: '/'})
  .then(function(registration) {
    // do something
  }).catch(function(error) {
    // do something
  });
}
Copy the code
/ / sw. Js file
self.addEventListener('install'.function(event) {
  // do something
});
self.addEventListener('activate'.function (event) {
  // do something
})


/* * The most important */
self.addEventListener('fetch'.function (event) {
  /** 1. Operate "offline data" and "real-time data" via CacheStorage and Cache apis. The data returned to the client is classified into the following types: 1. Network First: Network First policy 2. Cache First: Cache First policy 3. 4. Cache Only: reads resources Only from the Cache. * /
})

Copy the code
The working process
Matters needing attention
  • The Service Worker file is executed only once during the first registration
  • The installation,The activationThe process is only thereFor the first timeThis is done once when executing the Service Worker file.
  • fetchThe event
    • The Service Worker registered for the first time failed to block requests for the current page.
    • Service workers that are not registered for the first time can control the current page and block requests.
    • Reason: Why was the network request not intercepted the first time? Mainly because the registration of the Service Worker is oneasynchronousThe process of activating the current page after the request is completeIt has been sent.Because theTime too lateAt this point, no request can be intercepted and you can only waitThe next timeVisit again

Service Worker update mechanism
skipWaiting
  • Once the Service Worker is updated, it needs to wait until all terminals are updatedShut downAfter that, re-opening the page to activate the new Service Worker is too complicated. Typically, developers want the new Service Worker to be activated as soon as the Service Worker detects an update.

The Service Worker debugging
Local data storage

After the above foreshadowing, now can happily operate offline data and real-time data, first look at a section of code, after the supplement!

const CACHE_NAME = 'fed-cache'
const Self = globalThis

Self.addEventListener('install'.function (event) {
  Self.skipWaiting()
  Self.caches.open(CACHE_NAME)
})
Self.addEventListener('fetch'.function (event) {
  /* * Whether there is a network * Yes: the network request is made and the cache data is updated (keep the data relatively new) * No: the cache is offline */
  if (Self.navigator.onLine) {
    util.fetchPut(event.request.clone())
  } else {
    event.respondWith(
      caches.match(event.request).then((response) = > {
        return response
      })
    )
  }
})

let util = {
  fetchPut: function (request) {
    return fetch(request).then((response) = > {
      const responseClone = response.clone()
      if (util.noCache(response)) {
        return response
      }
      if (request.method === 'GET') {
        Self.caches.open(CACHE_NAME).then((cache) = > {
          cache.put(request, responseClone)
        })
      }
      return response
    })
  },
  noCache: function (response) {
    if(! response || response.status ! = =200|| response.type ! = ='basic'| |! response.url.includes('http') ||
      response.url.includes('vite')) {return true
    }
    return false}}Copy the code

CacheStorage API is used to manipulate data tables. The database Cache API is used to manipulate tables

CacheStorage API
  1. Cachestorage.open () creates/opens a database
  2. CacheStorage.match() 在All databasesRetrieves the returns that meet the criteriaResponseobject
  3. Cachestorage.has () Specifies whether a database exists
  4. Cachestorage.delete () deletes a database
  5. Cachestorage.keys () iterates over all databases, returning an array (containing the database name)
Cache API
  1. Cache.match(request, options) Queries single data
  2. Cache.matchAll(request, options) Queries multiple data sets
  3. Cache.add(request) Adds a data item
  4. Cache.addall (requests) Added multiple requests
  5. Cache. Put (Request, response) Adds a piece of data
  6. Cache.delete(request, options) Deletes a piece of data
  7. Cache.keys(request, options) traverses the table
Cache space usage

Mainly used to manage space memory, to reach the limit of periodic processing.

/** * Query the current cache space usage * cache resource expiration and cleanup work, try to avoid passive trigger browser resource cleanup */
navigator.storage.estimate().then((estimate) = > {
  // Total storage space allocated by the device for the current domain name
  console.log(estimate.quota)
  // Storage space used by the current domain name
  console.log(estimate.usage)
})
Copy the code
FetchEvent
  1. FetchEvent.respondWith()Mainly to prevent asynchronous operations, andasync awaitFeel the same, expand and extendfetchThe role of the event lifecycle
 // Incorrect usage
self.addEventListener('fetch'.event= > {
    // Since fetch is asynchronous, there is a possibility that the FETCH code has been executed and setTimeout has not been triggered
    setTimeout(() = > {
      event.respondWith(new Response('Hello World! '))},1000)})Copy the code
// Correct usage

// Wait 1 second before asynchronously returning the Response object
event.respondWith(new Promise(resolve= > {
  setTimeout(() = > {
    resolve(new Response('Hello World! '))},1000)}))Copy the code
  1. ExtendableEvent.waitUntil()Method tells the event distributor that the event is still in progress. This method can also be used to detect the success of an ongoing task. In the case of the service worker thread, this method tells the browser that the event continues until the promise is resolved and that the browser should not terminate the service worker thread until the asynchronous operation in the event completes. In a wordLife cycle extensionThat can be used toinstall,fetchThe event
addEventListener('install'.event= > {
  const preCache = async() = > {const cache = await caches.open('static-v1');
    return cache.addAll([
      '/'.'/about/'.'/static/styles.css'
    ]);
  };
  event.waitUntil(preCache());
});
Copy the code
communicationClients 、Client
 // main.js (main thread)
 navigator.serviceWorker.addEventListener('message'.(event) = > {
   console.log(`message: ${event.data}`)})/ / sw. Js file
  self.clients.matchAll().then(allClients= >{
    allClients.forEach(client= > {
      client.postMessage('I am Rainy')}); })Copy the code
One last point to note
  1. Cache.put.Cache.addandCache.addAllCan only be used for GET requests.
  2. ServiceWorker,fetchTo intercept,axiosno
Refer to the article
  1. Service Worker