18

我在我的页面上注册了一个 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 是最好的方式去......?

4

2 回答 2

30

所以事实证明,你实际上不能从你的应用程序调用一个 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 中调用正确的函数。要将结果返回给应用程序代码,您还需要将 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'});
于 2015-02-14T08:28:14.857 回答
2

要将数据传递给您的服务人员,上述方法是一个好方法。但万一,如果有人仍然很难实现它,那么还有另一个黑客可以解决这个问题,

1 - 在加载 service-worker 时附加数据以获取参数(例如, from sw.js-> sw.js?a=x&b=y&c=z

2- 现在在服务工作者中,使用self.self.location.search.

请注意,只有当您传递的数据不会经常针对特定客户端更改时,这才是有益的,否则它将不断更改该特定客户端的服务工作者的加载 url,并且每次客户端重新加载或重新访问时,新的服务工作者已安装。

于 2017-04-20T00:15:59.003 回答