1. 程式人生 > 其它 >關於Service Worker

關於Service Worker

Service Worker

含義

Service Worker 首先是一個執行在後臺的 Worker 執行緒,然後它會長期執行,充當一個服務,很適合那些不需要網頁或使用者互動的功能。它的最常見用途就是攔截和處理網路請求。

Service Worker 是一個後臺執行的指令碼,充當一個代理伺服器,攔截使用者發出的網路請求,比如載入指令碼和圖片。Service Worker 可以修改使用者的請求,或者直接向用戶發出迴應,不用聯絡伺服器,這使得使用者可以在離線情況下使用網路應用。它還可以在本地快取資原始檔,直接從快取載入檔案,因此可以加快訪問速度。

  1. if ('serviceWorker' in navigator) {
  2. window.addEventListener('load', function() {
  3.  `navigator.serviceWorker.register('/service-worker.js');`
    
  4. });
  5. }

上面程式碼確認瀏覽器支援 Service Worker 以後,會註冊一個 Service Worker。

為了節省記憶體,Service worker 在不使用的時候是休眠的。它也不會儲存資料,所以重新啟動的時候,為了拿到資料,最好把資料放在 IndexedDb 裡面。

Service Worker 是事件驅動的。

下面是攔截請求的例子。

  1. self.addEventListener('fetch', (event) => {
  2. event.waitUntil(
  3.  `if (event.request.url.includes('/product') {`
    
  4.    `let productId = event.data.productId`
    
  5.    `let productCount = getProductData(productId)`
    
  6.    `indexedDB.open('store', 1, (db) => {`
    
  7.      `let productStore = db.createObjectStore('products', { keyPath: 'id' })`
    
  8.      `productStore.put({ id: productId, count: ++productCount })`
    
  9.    `})`
    
  10.  `})`
    
  11. )
  12. })

Service Worker 不能直接操作 DOM。

使用步驟

登記

使用 service worker 的第一步,就是告訴瀏覽器,需要註冊一個 service worker 指令碼。

  1. navigator.serviceWorker.register('sw.js'.then(() => {
  2. console.info('註冊成功')
  3. }).catch((err) => {
  4. console.error('註冊失敗')
  5. })

上面程式碼的sw.js就是需要瀏覽器註冊的 service worker 指令碼。注意,這個指令碼必須與當前網址同域,service worker 不支援跨與指令碼。另外,sw.js必須是從 HTTPS 協議載入的。

預設情況下,Service worker 只對根目錄/生效,如果要改變生效範圍,可以執行下面的程式碼。

  1. navigator.serviceWorker.register(
  2. '/service-worker.js',
  3. { scope: '/products/fashion' }
  4. )

安裝

一旦登記成功,接下來都是 service worker 指令碼的工作。下面的程式碼都是寫在 service worker 腳本里面的。

登記後,就會觸發install事件。service worker 指令碼需要監聽這個事件。

  1. self.addEventListener('install', event => {

  2. event.waitUntil(() => console.info('安裝完成'))

  3. })

event.waitUntil()方法為事件完成後指定回撥函式。

  1. self.addEventListener('install', (event) => {
  2.  `let CACHE_NAME = 'xyz-cache'`
    
  3.  `let urlsToCache = [`
    
  4.      `'/',`
    
  5.      `'/styles/main.css',`
    
  6.      `'/scripts/bundle.js'`
    
  7.  `]`
    
  8.  `event.waitUntil(`
    
  9.      `caches.open(CACHE_NAME)`
    
  10.      `.then (cache => cache.addAll(urlsToCache))`
    
  11.  `)`
    
  12. })

啟用

安裝完成後,service worker 就會等待啟用。

  1. self.addEventListener('activate', (event) => {

  2.  `let cacheWhitelist = ['products-v2']`
    
  3.  `event.waitUntil(`
    
  4.      `caches.keys().then (cacheNames => {`
    
  5.          `return Promise.all(`
    
  6.              `cacheNames.map( cacheName => {`
    
  7.                  `if (cacheWhitelist.indexOf(cacheName) === -1) {`
    
  8.                      `return caches.delete(cacheName)`
    
  9.                  `}`
    
  10.              `})`
    
  11.          `)`
    
  12.      `})`
    
  13.  `)`
    
  14. })

Service Worker 與網頁的通訊

  1. self.addEventListener('activate', (event) => {
  2.  `event.waitUntil(`
    
  3.      `self.clients.matchAll().then ( (client) => {`
    
  4.          `client.postMessage({`
    
  5.              `msg: 'Hey, from service worker! I\'m listening to your fetch requests.',`
    
  6.              `source: 'service-worker'`
    
  7.          `})`
    
  8.      `})`
    
  9.  `)`
    
  10. })

上面程式碼中,Service Worker 監聽activate事件,然後向客戶端傳送一條資訊。

客戶端需要部署訊息監聽程式碼。

  1. this.addEventListener('message', (data) => {
  2.  `if (data.source == 'service-worker') {`
    
  3.      `console.log(data.msg)`
    
  4.  `}`
    
  5. })