Service Worker

簡(jiǎn)介

service worker通過(guò)攔截fetch事件,處理網(wǎng)絡(luò)請(qǐng)求。使用promise異步處理,所以不會(huì)阻塞主進(jìn)程的執(zhí)行。常用于借助Cache API緩存資源。還可以使用Push API實(shí)現(xiàn)推送通知(Safari不支持)、Background Synchronization后臺(tái)同步(Safari、Firefox不支持)等功能。

dist vs memory vs sw

瀏覽器為了提升訪問(wèn)的速度,會(huì)將緩存資源分為內(nèi)存緩存memory cache與磁盤(pán)緩存dist cache,小資源在短時(shí)間內(nèi)會(huì)被放在內(nèi)存中,加快訪問(wèn)的速度。值得注意的是這個(gè)存放目前沒(méi)有標(biāo)準(zhǔn),所以不同瀏覽器存儲(chǔ)的策略有些不同。

在資源緩存后,再次訪問(wèn)資源,瀏覽器會(huì)先檢測(cè)內(nèi)存有無(wú)資源,再發(fā)起fetch請(qǐng)求。所以service worker無(wú)法攔截內(nèi)存中的資源,但可以處理磁盤(pán)上的資源。

service worker利用Cache API緩存資源到磁盤(pán)中。而瀏覽器在管理磁盤(pán)的使用時(shí),也有可能刪除已緩存的資源。

在service worker未啟動(dòng)或停止運(yùn)行時(shí),瀏覽器需要先啟動(dòng)service worker再請(qǐng)求,所以可能會(huì)因此延遲一點(diǎn)時(shí)間。

總結(jié):

優(yōu)先級(jí): memory > sw > dist

加載速度: memory > dist > sw

service-worker優(yōu)點(diǎn):

  1. 完全控制網(wǎng)絡(luò)請(qǐng)求,可以設(shè)置請(qǐng)求的響應(yīng)頭
  2. 限制緩存的資源數(shù)量
  3. 自定義過(guò)期策略
  4. 可以使用indexDB存儲(chǔ)數(shù)據(jù),使用postMessage傳遞信息
  5. Disabled Cache不會(huì)清除緩存
  6. 支持離線訪問(wèn)網(wǎng)站

service-worker缺點(diǎn):

  1. 無(wú)法訪問(wèn)DOM,無(wú)法使用同步方法,如localStorage
  2. 必須再https環(huán)境下使用
  3. 需要在作用范圍的根目錄下創(chuàng)建service-worker,如要將全局的頁(yè)面進(jìn)行管理,就需要在根目錄下注冊(cè)
  4. 速度比瀏覽器緩存慢
  5. 在存在memory cache的情況下,無(wú)法更新緩存

緩存功能

service worker通過(guò)Cache API進(jìn)行緩存時(shí),有兩種不同的緩存方式,一種是預(yù)緩存,另一種是運(yùn)行時(shí)緩存。

預(yù)緩存通常在service worker安裝階段進(jìn)行,通過(guò)預(yù)緩存可以提前加載資源。但需要注意加載資源的時(shí)機(jī)與數(shù)量。

運(yùn)行時(shí)緩存是用于緩存已訪問(wèn)的資源,優(yōu)化資源的再次獲取。

運(yùn)行時(shí)緩存策略

  • Cache First 緩存優(yōu)先,無(wú)緩存請(qǐng)求網(wǎng)絡(luò)資源
  • Network First 網(wǎng)絡(luò)優(yōu)先,無(wú)網(wǎng)絡(luò)使用緩存資源
  • Network Only 只通過(guò)網(wǎng)絡(luò)獲取資源
  • Cache Only 只通過(guò)緩存獲取資源,需配合預(yù)緩存
  • Stale-While-Revalidate 緩存優(yōu)先,然后會(huì)發(fā)起請(qǐng)求更新緩存

實(shí)戰(zhàn)

service worker的生命周期為:注冊(cè)(register) -> 安裝(install) -> 激活(active)。在安裝后service work就會(huì)激活,只有激活后才會(huì)生效。

要注冊(cè)service worker需要提供service-worker.js,用于描述service worker的用途,注意service-worker.js文件的位置決定了service-worker控制的頁(yè)面,對(duì)于service-worker.js文件外部的頁(yè)面是無(wú)法控制的。注意文件的位置限制的是service-worker控制的頁(yè)面,而不是請(qǐng)求的地址,service-worker依然能控制從當(dāng)前頁(yè)面發(fā)送到外部包括跨域的請(qǐng)求。

此處不展開(kāi)描述原生service worker的配置方法。

為了方便使用,google推出了service-worker-workerbox簡(jiǎn)化使用,只需要簡(jiǎn)單的配置就可以自動(dòng)生成service-worker.js文件。

而對(duì)于注冊(cè)與安裝的命令也可以使用register-service-worker庫(kù)。


聚焦到具體的項(xiàng)目中。

目前項(xiàng)目中使用了umi的框架,所以需在umi的config文件中導(dǎo)入workbox-webpack-plugin庫(kù)。

import { defineConfig } from 'umi';
import { GenerateSW } from 'workbox-webpack-plugin';
export default defineConfig({
  .....other config
 chainWebpack(memo) {
    // workbox 配置
    memo.plugin('workbox').use(GenerateSW, [
      {
        clientsClaim: true, // Service Worker 被激活后使其立即獲得頁(yè)面控制權(quán)
        cleanupOutdatedCaches: true, //刪除過(guò)時(shí)、老版本的緩存
        include: ['**/*.{html,js,css,png.jpg}'], // 匹配的文件
        exclude: ['service-wroker.js'], // 忽略的文件
        runtimeCaching: [
          {
            urlPattern: /.*\.js.*/i,
            handler: 'CacheFirst',
            options: {
              cacheName: 'seed-js',
              expiration: {
                maxEntries: 20, //最多緩存20個(gè),超過(guò)的按照LRU原則刪除
                maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
              },
            },
          },
          {
            urlPattern: /.*css.*/,
            handler: 'CacheFirst',
            options: {
              cacheName: 'seed-css',
              expiration: {
                maxEntries: 30, //最多緩存30個(gè),超過(guò)的按照LRU原則刪除
                maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
              },
            },
          },
          {
            urlPattern: /.*(png|svga).*/,
            handler: 'CacheFirst',
            options: {
              cacheName: 'seed-image',
              expiration: {
                maxEntries: 30, //最多緩存30個(gè),超過(guò)的按照LRU原則刪除
                maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
              },
            },
          },
        ],
      },
    ]);
  },
})

然后在app.ts中調(diào)用register-service-worker,注冊(cè)service worker。

import { register } from 'register-service-worker';
import { isBrowser } from 'umi';

if (process.env.NODE_ENV === 'production' && isBrowser()) {
  register(`/service-worker.js`, {
    ready(registration) {
      console.log('Service worker is active.');
    },
    registered(registration) {
      console.log('Service worker has been registered.');
    },
    cached(registration) {
      console.log('Content has been cached for offline use.');
    },
    updatefound(registration) {
      console.log('New content is downloading.');
    },
    updated(registration) {
      console.log('New content is available; please refresh.');
    },
    offline() {
      console.log(
        'No internet connection found. App is running in offline mode.',
      );
    },
    error(error) {
      console.error('Error during service worker registration:', error);
    },
  });
}

這樣就完成了一個(gè)簡(jiǎn)單的service worker配置。

參考

stackoverflow-why-use-a-service-worker

ServiceWorker issue: Difference between disk and memory cache

Service worker caching and HTTP caching

Introduction to Workbox and service workers

umi3.x配置service worker

How to use PWA on umi 3.0

register-service-worker

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容