PWA(Progressive Web App)入门系列:消息通讯
前言
serviceWorker 的能力決定它要處理的事情,網站頁面的部分邏輯處理會轉移到 serviceWorker 層進行處理,這里就要頁面層和 serviceWorker 層進行交互來實現消息通訊。
下面就說一下兩個環境下的消息通訊。
窗口向 serviceWorker 通訊
這里列舉出窗口層到 serviceWorker 層的通訊方法。
1. ServiceWorker.postMessage
頁面層可以通過 ServiceWorker 接口的 postMessage 來實現頁面到 serviceWorker 環境的通訊。
ServiceWorker 接口的獲取:
ServiceWorker 接口獲取有兩種方式
- navigator.serviceWorker.controller,常用這種方式。
- navigator.serviceWorker.ready.then(swReg => swReg[state]):state 為 {installing, waiting, active} 。
當 postMessage 后,serviceWorker 環境采用 onmessage 事件進行處理。
發送消息:
發送消息實現:
index.html
// 頁面 window 環境if(navigator.serviceWorker.controller) { // 需要判斷是否受控navigator.serviceWorker.controller.postMessage('消息'); // postMessage 的第一個參數可以是由結構化克隆算法處理的任何值或JavaScript對象,也包括循環引用。 } 復制代碼sw.js
// serviceWorker 環境self.addEventListener("message", e => {console.log("message", e);// 從 e.data 里面取 postMessage 過來的數據 }) 復制代碼接收消息:
頁面層 window 環境下接收消息需要在 ServiceWorkerContainer 接口上監聽 onmessage:
navigator.serviceWorker.onmessage 復制代碼serviceWorker 層做定向 Client 的獲取有以下方式:
// 1. 通過 e.source.id 來定向發送消息self.addEventListener("message", e => {const client = await self.clients.get(e.source.id);client.postMessage('發給頁面層的消息'); })// 2. 直接 e.source 來定向發送消息self.addEventListener("message", e => {e.source.postMessage('發給頁面層的消息'); }) 復制代碼2. ServiceWorkerRegistration.sync.register
第二種方式,是使用 sync 的方式來實現頁面層到 serviceWorker 層的通訊。
這種通訊的弊端是單向的,且不可控。
但優勢也很明顯,對于后臺同步十分有用,一旦注冊 sync 在 online 的狀態下會立即觸發 serviceWorker 環境下的 onsync 事件,serviceWorker 可根據具體邏輯處理,直到 e.waitUntil 返回 Promise.resolve() 才會完成 sync,并把 sync 的 tag 清除,否則會一直按照某個周期執行,知道 e.lastChance == true。
// 頁面層環境navigator.serviceWorker.ready.then(swReg => {swReg.sync.register('同步tag') }) 復制代碼// serviceWorker 層環境self.addEventListener("sync", e => {if(e.tag == '同步tag') {e.waitUntil(new Promise((res, rej) => {// 邏輯處理 ...return res();}))} }) 復制代碼3. MessageChannel
MessageChannel 是一個點對點的消息通道,可以很方便的實現消息的雙向通訊。
構造函數:
構造函數很簡單,不需要任何參數
var channel = new MessageChannel(); 復制代碼屬性:
- MessageChannel.port1
- MessageChannel.port2
屬性中的兩個 port 為 MessagePort 接口實現,具備以下方法:
- postMessage
- start
- close
具備事件監聽:MessagePort.onmessage。
這里發消息時,主要以環境下的 postMessage 配合使用。
// 頁面層環境if(navigator.serviceWorker.controller) {var c = new MessageChannel();c.port1.onmessage = e => {// 收到傳給 port1 的消息}// 向 port2 發送消息navigator.serviceWorker.controller.postMessage('消息', [c.port2]) } 復制代碼// serviceWorker 層self.addEventListener("message", e => {// 從 e.ports 里取 MessagePorte.ports[0] && e.ports[0].postMessage('向port1發送消息') }) 復制代碼注意:MessageChannel 創建的通道會受 serviceWorker 的 stopWorker 影響,導致 MessageChannel 通道 close,也就是表現為通道只能用一次。所以使用 MessageChannel 通訊時,每次都要創建新的通道。
serviceWorker 向窗口通訊
上面說的是窗口頁面層向 serviceWorker 環境的通訊,同樣 serviceWorker 環境層也需要向頁面層通訊。
在 serviceWorker 環境下主要有兩種向頁面層通訊的方式。
1. BroadcastChannel
第一種是 BroadcastChannel,也就是廣播信道通訊。
構造函數:
構造函數很簡單,channel 參數為一個字符串。
var channel = new BroadcastChannel(channel); 復制代碼屬性:
- BroadcastChannel.name:構造時的信道名。
事件:
- onmessage
- onmessageerror
方法:
- postMessage()
- close()
2. client.postMessage
第二種就是獲取相應的 client 進行 postMessage。
如果從 onmessage 中,是可以獲取到相應的 sorce client 的,從而進行雙向通訊。但在自發情況下,只能對所有 client 進行廣播通訊。
// serviceWorker 環境clients.matchAll({type: "window" }) .then(windows => {for (const win of windows) {win.postMessage('發送消息到頁面');} }); 復制代碼博客名稱:王樂平博客
CSDN博客地址:blog.csdn.net/lecepin
本作品采用知識共享署名-非商業性使用-禁止演繹 4.0 國際許可協議進行許可。轉載于:https://juejin.im/post/5d067f22e51d457778117390
總結
以上是生活随笔為你收集整理的PWA(Progressive Web App)入门系列:消息通讯的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSS进阶(7)—— 内联元素的掌管者l
- 下一篇: haproxy对mysql集群进行负载均