动态

详情 返回 返回

ServiceWorker 使用 - 动态 详情

MDN 文檔

  • ServiceWorker

參考文章

  • Working with the JavaScript Cache API

代碼地址

目標

斷網情況下正常打開頁面,加載本地緩存數據

調試

chrome 控制枱 > Application > Service Workers

創建 serviceWorker

新建 sw.js 文件,初始化監聽事件:

//sw.js

// 版本號
const CACHE_VERSION = 'cache-v0'

// 安裝
self.addEventListener('install', (event) => {
    // sw.js 文件發生變動,就會執行 install 回調函數
  console.log('install')
})

// 激活
self.addEventListener('activate', (event) => {
  console.log('activate')
})

// 捕獲網絡請求
self.addEventListener('fetch', (event) => {})

register

註冊 serviceWorker:

navigator.serviceWorker.register("./sw.js",{scope:"/"}).then(
    registration => console.log("success"),
    error =>console.error("register error")
)

waitUntil

sw.js 文件發生變動後,雖然會執行 install 回調函數,但是新版本的腳本文件並沒有被激活。

激活 activate:

self.addEventListener('install', (event) => {
  console.log('install')
  //內容發生變化,直接進入 activate
  event.waitUntil(self.skipWaiting());
})

caches

存在全局的 caches 對象,可通過 caches.open(cacheName) 打開緩存對象或delete(cacheName) 刪除對象。

通過 open 獲得 Cache 主要包含以下幾個方法:

api 作用
Cache.addAll(requests) 返回Promise,給 cache 添加緩存請求
Cache.match(request, options) 返回Promise,匹配緩存對象已緩存請求
Cache.put(request, response) 返回Promise,獲取請求和保存響應結果
更詳細的api介紹請查看 Working with the JavaScript Cache API

流程

ServiceWorker 需要在服務中啓用

首頁 index.html

  • 加載樣式資源 index.css
  • 加載圖片資源
  • 請求服務數據 data.json
  • 響應數據渲染進app標籤
  • 註冊 ServiceWorker 服務
<html>
  <head>
    <title>service Worker</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div id="app"></div>
    <img
      src="https://blog.logrocket.com/wp-content/uploads/2020/06/cacheapi.png"
    />
    <script>
      ;(async () => {
        const registration = await navigator.serviceWorker.register('./sw.js', {
          scope: '/',
        })
      })()

      window.onload = function () {
        const xhr = new XMLHttpRequest()
        xhr.open('GET', './data.json')
        xhr.responseType = 'json'
        xhr.onload = () => {
          app.innerText = xhr.response.result
        }
        xhr.send(null)
      }
    </script>
  </body>
</html>

sw.js 流程

  • 聲明版本號

install

  • 獲得對應版本號cache
  • 添加需要緩存的資源路徑
  • 進入 activate

activate

  • 獲得已經註冊的caches版本
  • 遍歷版本號,對比當前最新版本號
  • 新舊版本號不匹配,清空舊版本

fetch

  • 截取請求資源
  • 打開當前版本號的緩存資源
  • 匹配到緩存結果返回
  • 不在緩存的資源再fetch服務器資源
  • 如果是圖片資源,加入到緩存
// sw.js
const CACHE_VERSION = 'cache-v0'

// 只要 sw.js 發生變化,就會執行 install
self.addEventListener('install', (event) => {
  console.log('install')
  //內容發生變化,直接進入 activate
  // event.waitUntil(self.skipWaiting());

  // 進入緩存,添加緩存資源路徑,接着進入 activate
  event.waitUntil(
    caches
      .open(CACHE_VERSION)
      .then((cache) => cache.addAll(['/', '/index.css']))
      .then(self.skipWaiting)
  )
})

self.addEventListener('activate', (event) => {
  console.log('activate')
  // 默認情況下,首次加載後不受控制,self.clients.claim 讓首次控制生效
  // event.waitUntil(self.clients.claim())

  // 判斷緩存資源,如果緩存版本修改,刪掉舊版本資源
  event.waitUntil(
    caches.keys().then((cahceNames) => {
      return Promise.all(
        cahceNames.map((cacheName) => {
          if (cacheName !== CACHE_VERSION) {
            console.log('clear', cacheName)
            return caches.delete(cacheName)
          }
        })
      )
    })
  )
})

self.addEventListener('fetch', (event) => {
  const url = event.request.url

  event.respondWith(
    caches.open(CACHE_VERSION).then(async (cache) => {
      // 匹配緩存中的請求資源
      let response = await cache.match(event.request)
      // 存在則返回
      if (response) return response

      // 否則請求服務器資源
      response = await fetch(event.request)
      // 緩存服務器資源
      if (/\.(jpg|png)$/g.test(url)) {
        cache.put(event.request, response.clone())
      }

      return response
    })
  )
})

Add a new 评论

Some HTML is okay.