PWA(Progressive Web App)入門系列:消息通信

前言

serviceWorker 的能力決定它要處理的事情,網站頁面的部分邏輯處理會轉移到 serviceWorker 層進行處理,這裏就要頁面層和 serviceWorker 層進行交互來實現消息通信。html

下面就說一下兩個環境下的消息通信。算法


窗口向 serviceWorker 通信

這裏列舉出窗口層到 serviceWorker 層的通信方法。windows

1. ServiceWorker.postMessage

頁面層能夠經過 ServiceWorker 接口的 postMessage 來實現頁面到 serviceWorker 環境的通信。函數

ServiceWorker 接口的獲取:post

ServiceWorker 接口獲取有兩種方式網站

  • navigator.serviceWorker.controller,經常使用這種方式。
  • navigator.serviceWorker.ready.then(swReg => swReg[state]):state 爲 {installing, waiting, active}

當 postMessage 後,serviceWorker 環境採用 onmessage 事件進行處理。ui

發送消息:spa

發送消息實現:.net

index.html3d

// 頁面 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 裏取 MessagePort
	e.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()
// 頁面層

var bc1 = new BroadcastChannel('c1');

bc1.onmessage = e => {
	// 頁面層收到廣播,邏輯處理
}
複製代碼
// serviceWorker 層

var bc1 = new BroadcastChannel('c1');

bc1.postMessage('發送廣播消息');
複製代碼

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 國際許可協議進行許可。
相關文章
相關標籤/搜索