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 国际许可协议进行许可。
相关文章
相关标签/搜索