如何从我的页面中调用我的 ServiceWorker 上的方法?
How do I call a method on my ServiceWorker from within my page?
我在我的页面上注册了一个 ServiceWorker,我想将一些数据传递给它,以便它可以存储在 IndexedDB 中,稍后用于网络请求(它是一个访问令牌)。
仅使用网络请求并使用 fetch 在 SW 端捕获它们是正确的做法,还是有更聪明的方法?
未来的读者请注意与我有类似问题的人:
设置 SW 注册对象的属性,例如将 self.registration.foo 设置为 service worker 中的一个函数并在页面中执行以下操作:
navigator.serviceWorker.getRegistration().then(function(reg) { reg.foo; })
结果 TypeError: reg.foo is not a function
。我认为这与 ServiceWorker 的生命周期有关,这意味着您无法修改它并期望将来可以访问这些修改,因此任何带有 SW 的接口都可能必须是 postMessage 样式,所以也许只使用 fetch 是最好的方法...?
所以事实证明你实际上不能从你的应用程序调用 SW 中的方法(由于生命周期问题),所以你必须使用 postMessage API 来传递序列化 JSON 消息(因此没有传递回调等)。
您可以使用以下应用代码向控制软件发送消息:
navigator.serviceWorker.controller.postMessage({'hello': 'world'})
结合以下SW代码:
self.addEventListener('message', function (evt) {
console.log('postMessage received', evt.data);
})
这会在我的 SW 控制台中产生以下结果:
postMessage received Object {hello: "world"}
因此,通过传入一条消息(JS 对象)来指示我要调用的函数和参数,我的事件侦听器可以接收它并在 SW 中调用正确的函数。要 return 应用程序代码的结果,您还需要将 MessageChannel 的端口传递到 SW,然后通过 postMessage 进行响应,例如在您创建的应用程序中,您将通过 MessageChannel 发送数据:
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
console.log(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 中通过它进行响应:
evt.ports[0].postMessage({'hello': 'world'});
要将数据传递给您的服务工作者,上面提到的是一个很好的方法。但以防万一,如果有人仍然难以实现它,那么还有其他方法可以解决这个问题,
1 - 在加载 service-worker 时附加数据以获取参数(例如,从 sw.js
-> sw.js?a=x&b=y&c=z
)
2- 现在在 service worker 中,使用 self.self.location.search
.
获取这些数据
注意,只有当您传递的数据不经常为特定客户端更改时,这才有用,否则它会不断更改 service worker 的加载 url特定的客户端,每次客户端重新加载或重新访问时,都会安装新的 service worker。
我在我的页面上注册了一个 ServiceWorker,我想将一些数据传递给它,以便它可以存储在 IndexedDB 中,稍后用于网络请求(它是一个访问令牌)。
仅使用网络请求并使用 fetch 在 SW 端捕获它们是正确的做法,还是有更聪明的方法?
未来的读者请注意与我有类似问题的人:
设置 SW 注册对象的属性,例如将 self.registration.foo 设置为 service worker 中的一个函数并在页面中执行以下操作:
navigator.serviceWorker.getRegistration().then(function(reg) { reg.foo; })
结果 TypeError: reg.foo is not a function
。我认为这与 ServiceWorker 的生命周期有关,这意味着您无法修改它并期望将来可以访问这些修改,因此任何带有 SW 的接口都可能必须是 postMessage 样式,所以也许只使用 fetch 是最好的方法...?
所以事实证明你实际上不能从你的应用程序调用 SW 中的方法(由于生命周期问题),所以你必须使用 postMessage API 来传递序列化 JSON 消息(因此没有传递回调等)。
您可以使用以下应用代码向控制软件发送消息:
navigator.serviceWorker.controller.postMessage({'hello': 'world'})
结合以下SW代码:
self.addEventListener('message', function (evt) {
console.log('postMessage received', evt.data);
})
这会在我的 SW 控制台中产生以下结果:
postMessage received Object {hello: "world"}
因此,通过传入一条消息(JS 对象)来指示我要调用的函数和参数,我的事件侦听器可以接收它并在 SW 中调用正确的函数。要 return 应用程序代码的结果,您还需要将 MessageChannel 的端口传递到 SW,然后通过 postMessage 进行响应,例如在您创建的应用程序中,您将通过 MessageChannel 发送数据:
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
console.log(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 中通过它进行响应:
evt.ports[0].postMessage({'hello': 'world'});
要将数据传递给您的服务工作者,上面提到的是一个很好的方法。但以防万一,如果有人仍然难以实现它,那么还有其他方法可以解决这个问题,
1 - 在加载 service-worker 时附加数据以获取参数(例如,从 sw.js
-> sw.js?a=x&b=y&c=z
)
2- 现在在 service worker 中,使用 self.self.location.search
.
注意,只有当您传递的数据不经常为特定客户端更改时,这才有用,否则它会不断更改 service worker 的加载 url特定的客户端,每次客户端重新加载或重新访问时,都会安装新的 service worker。