Niro
Niro

Reputation: 334

communication between service worker instances

I'm trying to establish a communication channel between an installing service worker and an activated service worker. I've tried to do the following:

on the installing service worker:

 if ((self.registration.active == null) ||
     (self.registration.active.state != "activated")) {
      return;
 }

 var messageChannel = new MessageChannel();
 messageChannel.port1.onmessage = function(event){
      if (event.data.error) {
           console.log("got error from active");
      }

      else {
           console.log("got answer from active");
      }
 };

 self.registration.active.postMessage({message: 'hey', port: messageChannel.port2}, [messageChannel.port2]);

on the active service worker:

 self.addEventListener('message', function(event) {
      console.log('received message');
 });

This isn't working, I'm getting nothing... Ideas?

Upvotes: 0

Views: 1212

Answers (2)

Niro
Niro

Reputation: 334

Here's how I ended up implementing this.

Each serviceWorker at startup (code at the worker's global scope) connects to a broadcast channel like so:

 var comChannel = new BroadcastChannel('SWCom');
 comChannel.addEventListener('message', event => {
      handleMessageEvent(event);
 });

This channel is shared only between service workers. To post a message to other SW, a SW can just broadcast on the channel comChannel.postMessage('hey there'); and any registered listener will be invoked.

One complication I had, not really related to the channel, is that I had a hard time identifying each SW life cycle state. If I want to communicate between SW it can't really serve any purpose if I don't know who's whom within each one of them. A SW cannot currently get a ref to its own ServiveWorker object, there's an open issue about it in the standard - https://github.com/w3c/ServiceWorker/issues/1077

In my usecase, I bypassed this limitation by performing the communication upon install (fits my needs...), like so:

 self.addEventListener('install', function(event) {
      if (self.registration.active != null) {
           // if we got here it means this is a new SW that's
           // starting install and there's an active one running.
           // So we can send a message on the broadcast channel,
           // whomever answers should be the active SW.
      }

      // ..
      // installation code
      // ..
 }

One thing to note - I'm not sure this is well implemented. I believe there are other states a SW can be at (redundant, deleted?, others?), so maybe there can be more then two ServiceWorkers alive, and then the assumption on the identity of the answering side on the channel might be wrong...

Upvotes: 1

anthumchris
anthumchris

Reputation: 9072

Jake provides some excellent examples of messaging that you may be able to derive a solution from. https://gist.github.com/jakearchibald/a1ca502713f41dfb77172be4523a9a4c

You may need to use the page itself as a proxy for sending/receiving messages between Service workers:

[SW1] <== message ==> [Page JS] <== message ==> [SW2]

Upvotes: 0

Related Questions