serviceWorker 的能力決定它要處理的事情,網站頁面的部分邏輯處理會轉移到 serviceWorker 層進行處理,這裏就要頁面層和 serviceWorker 層進行交互來實現消息通信。html
下面就說一下兩個環境下的消息通信。算法
這裏列舉出窗口層到 serviceWorker 層的通信方法。windows
頁面層能夠經過 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('發給頁面層的消息');
})
複製代碼
第二種方式,是使用 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();
})
)
}
})
複製代碼
MessageChannel 是一個點對點的消息通道,能夠很方便的實現消息的雙向通信。
構造函數:
構造函數很簡單,不須要任何參數
var channel = new MessageChannel();
複製代碼
屬性:
屬性中的兩個 port 爲 MessagePort 接口實現,具有如下方法:
具有事件監聽: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 環境下主要有兩種向頁面層通信的方式。
第一種是 BroadcastChannel,也就是廣播信道通信。
構造函數:
構造函數很簡單,channel
參數爲一個字符串。
var channel = new BroadcastChannel(channel);
複製代碼
屬性:
BroadcastChannel.name
:構造時的信道名。事件:
方法:
// 頁面層
var bc1 = new BroadcastChannel('c1');
bc1.onmessage = e => {
// 頁面層收到廣播,邏輯處理
}
複製代碼
// serviceWorker 層
var bc1 = new BroadcastChannel('c1');
bc1.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