如何从我的页面中调用ServiceWorker上的方法?

时间:2015-02-14 08:10:58

标签: service-worker

我在我的页面上注册了一个ServiceWorker,并希望将一些数据传递给它,以便它可以存储在IndexedDB中,以后用于网络请求(它是一个访问令牌)。

使用网络请求并使用fetch在SW端捕获它们是正确的,还是有更聪明的东西?

请注意未来读者对我有类似的想法:

在SW注册对象上设置属性,例如将self.registration.foo设置为服务工作者中的函数并在页面中执行以下操作:

navigator.serviceWorker.getRegistration().then(function(reg) { reg.foo; })

'TypeError:reg.foo不是函数'的结果。我认为这与ServiceWorker的生命周期有关,这意味着你无法修改它并期望将来可以访问这些修改,因此任何具有SW的接口都可能必须是postMessage样式,所以也许只使用fetch是最好的方式......?

2 个答案:

答案 0 :(得分:19)

事实证明你实际上无法从你的应用程序中调用SW中的方法(由于生命周期问题),所以你必须使用postMessage API来传递序列化的JSON消息(所以没有传递回调等)

您可以使用以下应用代码向控制SW发送消息:

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'});

答案 1 :(得分:1)

要将数据传递给服务工作者,上面提到的是一种好方法。但是,万一,如果有人仍然很难实现这一点,那么还有另外一个黑客,

1 - 在加载service-worker时将数据附加到get参数(例如,来自sw.js - > sw.js?a=x&b=y&c=z

2-现在在服务工作者中,使用self.self.location.search获取这些数据。

注意,只有当您传递的数据不经常更改为特定客户端时,这将是有益的,否则它将继续更改该特定客户端的服务工作者的加载URL以及每次客户端重新加载时或者重新访问,安装了新的服务工作者。