如何从我的页面中调用我的 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。