Chrome ServiceWorker postMessage
Chrome ServiceWorker postMessage
我尝试 postMessage
在 Web 应用程序和相应的 Service Worker 之间。 Service Worker 已成功注册并运行至今。
不幸的是,我注意到一些奇怪的行为:
navigator.serviceWorker.controller
总是 null
。
- 在service worker端,我实现了
postMessage
如下:
self.addEventListener('message', function (evt) {
console.log('postMessage received', evt);
});
不幸的是,post 返回原点 evt.origin=''
和 evt.source=null
的重要字段不包含所需的值。尽管如此,我总是收到发送的 evt.data
.
你知道如何post返回吗?
非常感谢!
安迪
this demo 中显示了一种将工作人员的响应发送回受控应用程序的方法,并按以下方式完成(我还没有实际测试过,但演示运行良好并且代码似乎与规格一致)。
在主页中:
function sendMessage(message) {
// This wraps the message posting/response in a promise, which will
// resolve if the response doesn't contain an error, and reject with
// the error if it does. If you'd prefer, it's possible to call
// controller.postMessage() and set up the onmessage handler
// independently of a promise, but this is a convenient wrapper.
return new Promise(function(resolve, reject) {
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
if (event.data.error) {
reject(event.data.error);
} else {
resolve(event.data);
}
};
// This sends the message data as well as transferring
// messageChannel.port2 to the service worker.
// The service worker can then use the transferred port to reply
// via postMessage(), which will in turn trigger the onmessage
// handler on messageChannel.port1.
// See
// https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
});
}
并且在 service worker 代码中:
self.addEventListener('message', function(event) {
event.ports[0].postMessage({'test': 'This is my response.'});
});
然后您应该能够使用 sendMessage
函数返回的 promise 来处理来自 service worker 的响应。
@GalBracha 问你是否可以在不先发送消息的情况下与客户沟通 - 是的!。这是一个简单的示例,说明当我想在收到推送通知时向客户发送消息时(不是在用户单击通知时,而是在服务人员收到事件时):
在您的客户端 js 中(服务工作者注册后等):
// navigator.serviceWorker.addEventListener('message', ... ) should work too
navigator.serviceWorker.onmessage = function (e) {
// messages from service worker.
console.log('e.data', e.data);
};
在您的服务工作者中,响应某些事件(可能是安装事件):
// find the client(s) you want to send messages to:
self.clients.matchAll(/* search options */).then( (clients) => {
if (clients && clients.length) {
// you need to decide which clients you want to send the message to..
const client = clients[0];
client.postMessage("your message");
}
诀窍是(显然?)将消息事件的侦听器附加到 serviceWorker 对象,而不是 window 对象。
广播频道API更容易
使用 Broadcast Channel API, compared to other methods.
在 service worker 和它的客户端之间来回发送信息要容易得多
这是广播的工作原理
在 service worker 和客户端中定义一个新的广播频道。
const channel4Broadcast = new BroadcastChannel('channel4');
向发送工作线程或客户端中的广播消息:
channel4Broadcast.postMessage({key: value});
要在工作器或客户端中接收广播消息:
channel4Broadcast.onmessage = (event) => {
value = event.data.key;
}
广播还允许在客户端的 web worker、客户端和 service worker 之间发送消息。
警告
虽然这种简单性是有代价的。按照目前的情况,the service worker will not wake up 接收广播消息。因此,它仅在 service worker 处于 运行(活动或等待)状态时起作用;即当客户可见时。尽管如此,这可能仍然有用,例如广播版本号或网络推送等
我尝试 postMessage
在 Web 应用程序和相应的 Service Worker 之间。 Service Worker 已成功注册并运行至今。
不幸的是,我注意到一些奇怪的行为:
navigator.serviceWorker.controller
总是null
。- 在service worker端,我实现了
postMessage
如下:
self.addEventListener('message', function (evt) {
console.log('postMessage received', evt);
});
不幸的是,post 返回原点 evt.origin=''
和 evt.source=null
的重要字段不包含所需的值。尽管如此,我总是收到发送的 evt.data
.
你知道如何post返回吗?
非常感谢!
安迪
this demo 中显示了一种将工作人员的响应发送回受控应用程序的方法,并按以下方式完成(我还没有实际测试过,但演示运行良好并且代码似乎与规格一致)。
在主页中:
function sendMessage(message) {
// This wraps the message posting/response in a promise, which will
// resolve if the response doesn't contain an error, and reject with
// the error if it does. If you'd prefer, it's possible to call
// controller.postMessage() and set up the onmessage handler
// independently of a promise, but this is a convenient wrapper.
return new Promise(function(resolve, reject) {
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
if (event.data.error) {
reject(event.data.error);
} else {
resolve(event.data);
}
};
// This sends the message data as well as transferring
// messageChannel.port2 to the service worker.
// The service worker can then use the transferred port to reply
// via postMessage(), which will in turn trigger the onmessage
// handler on messageChannel.port1.
// See
// https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
});
}
并且在 service worker 代码中:
self.addEventListener('message', function(event) {
event.ports[0].postMessage({'test': 'This is my response.'});
});
然后您应该能够使用 sendMessage
函数返回的 promise 来处理来自 service worker 的响应。
@GalBracha 问你是否可以在不先发送消息的情况下与客户沟通 - 是的!。这是一个简单的示例,说明当我想在收到推送通知时向客户发送消息时(不是在用户单击通知时,而是在服务人员收到事件时):
在您的客户端 js 中(服务工作者注册后等):
// navigator.serviceWorker.addEventListener('message', ... ) should work too
navigator.serviceWorker.onmessage = function (e) {
// messages from service worker.
console.log('e.data', e.data);
};
在您的服务工作者中,响应某些事件(可能是安装事件):
// find the client(s) you want to send messages to:
self.clients.matchAll(/* search options */).then( (clients) => {
if (clients && clients.length) {
// you need to decide which clients you want to send the message to..
const client = clients[0];
client.postMessage("your message");
}
诀窍是(显然?)将消息事件的侦听器附加到 serviceWorker 对象,而不是 window 对象。
广播频道API更容易
使用 Broadcast Channel API, compared to other methods.
在 service worker 和它的客户端之间来回发送信息要容易得多这是广播的工作原理
在 service worker 和客户端中定义一个新的广播频道。
const channel4Broadcast = new BroadcastChannel('channel4');
向发送工作线程或客户端中的广播消息:
channel4Broadcast.postMessage({key: value});
要在工作器或客户端中接收广播消息:
channel4Broadcast.onmessage = (event) => {
value = event.data.key;
}
广播还允许在客户端的 web worker、客户端和 service worker 之间发送消息。
警告
虽然这种简单性是有代价的。按照目前的情况,the service worker will not wake up 接收广播消息。因此,它仅在 service worker 处于 运行(活动或等待)状态时起作用;即当客户可见时。尽管如此,这可能仍然有用,例如广播版本号或网络推送等