Service Worker (Web)推送不完全實踐

toBeTheLight 發表於 2022-11-27

以下實踐結論來自 windows 平臺 Edge 瀏覽器與 mac 平臺 Chrome 瀏覽器

事件

// worker.js
self.addEventListener("install", (event) => {
  self.skipWaiting()
})
self.addEventListener('activate', (event) => {
  event.waitUntil(() => {})
})


self.addEventListener('push', (event) => {
  event.waitUntil(() => {})
})
self.addEventListener('sync', (event) => {
  event.waitUntil(() => {})
})

程式碼所包含的四個事件中,install 與 activate 事件是 service worker 的生命週期事件。

event.waitUntil 方法也是很重要的方法。

install:install 事件發生在 worker 被安裝或更新時,然後進入等待狀態,在某個時機進入啟用中,避免與舊的已啟用的 worker 衝突。呼叫 skipWaiting 可跳過等待。

activate:activate 事件表示當前 worker 已經正式工作。

push:push 事件是 web-push 能力的服務訊息推送事件。重點之一。

sync:sync 則是由頁面客戶端發起的,我們可以用來做一定的推送能力。重點之一。

Web Push

web push 是依賴於瀏覽器客戶端的推送能力,由瀏覽器廠商提供(大概)。可以在使用者訂閱後,在未開啟過(大概)站點的情況下收到推送訊息。

// client 部分,worker 為 serviceWorker.register 註冊後的例項
const pushSubscription = worker.pushManager
    .subscribe({
      applicationServerKey: urlBase64ToUint8Array(publicVapidKey),
      userVisibleOnly: true
    })
fetch('/server', pushSubscription)

subscribe 的引數 applicationServerKey 為服務生成的公鑰,完成訂閱後 pushSubscription 中會包含分配的 endpoint 資訊,即此客戶端接受訊息的推送地址。

然後需要將此 pushSubscription 資訊提交給使用者的服務,在服務中使用相關資訊進行訊息推送,請參考其他文章。

endpoint 在 Edge 中為 https://wns2-sg2p.notify.wind...,在 chrome 中為 google 的 gcm 地址,後者有眾所周知的連不上的問題。

如果需要使用瀏覽器的 web push 能力需要向廠商申請,需要進一步調研。

Sync

我們嘗試其他方式進行。

sync 如名是用來做同步的。需要客戶端程式碼發起同步註冊:

worker.sync.register('sync-name')

然後已註冊的 worker 即會觸發 sync 事件。此時 worker 內需要進行輪詢、長連結等方式進行訊息獲取,並呼叫通知進行展示,示例程式碼如下:

// worker.js 
self.addEventListener('sync', (event) => {
  function poll () {
    fetch('/data-server/').then(res => {
      self.registration.showNotification('來自輪詢的訊息', { body: res.data })
      setTimeout(() => {
        poll()
      }, 30 * 1000)
    })
  }
  poll()
}

看到這裡可能會覺得為什麼需要在 sync 中進行輪詢,為什麼不在 worker 中直接輪詢?

實踐發現 service-worker 在 tab 或瀏覽器退出後很快就會被回收,執行停止,這個時間最多也就 十幾秒。

event.waitUntil 接受一個 promise,會告訴事件分發器事件仍然在進行,通知避免瀏覽器終止 worker 執行緒的執行,為了延長 worker 執行緒存活時間,我們將 poll 包裝成一個不執行 resolve 的 promise 即可延長存活時間。
測試得在在關閉瀏覽器或頁籤後,最多執行了 3 分鐘左右(同時,出現了一個現象,worker 在 5 分鐘後又啟用了一輪,15 分鐘後又一輪,後續未觀察,但同時 poll 裡用來做標記的 id 變了)。並未達到長期存活的效果。