Service worker communicate to clients

Boris Barroso picture Boris Barroso · Feb 9, 2017 · Viewed 8.9k times · Source

I have been trying to send messages to clients from service worker but if I use

self.clients.matchAll()
.then((clients) => {
  clients.forEach(function(client) {
    client.postMessage({msg: 'Hello from SW'})
  })
})

it won't send to any client even if I have a tab open in the browser, but if I send a message from the client to the service worker

// client
navigator.serviceWorker.controller.postMessage({title: 'Send message from client'})

and in the service worker

self.addEventListener('message', function(event) {
  self.clients.fetchAll()
    .then((clients) => {
      clients.forEach(function(client) {
        client.postMessage({msg: 'Hello from SW'})
     })
  })
})

it can send a message and finds clients. what am I doing wrong?, should I use indexedDB instead?

Answer

Jeff Posnick picture Jeff Posnick · Feb 10, 2017

I don't believe that clients.fetchAll() exists. You probably mean clients.matchAll(), which should give you the behavior you describe:

self.clients.matchAll().then(clients => {
  clients.forEach(client => client.postMessage({msg: 'Hello from SW'}));
})

A nicer alternative allowing the service worker to communicate with clients, while avoiding having to send messages one-by-one, is to make use of the Broadcast Channel API. It is now supported in recent versions of Chrome as well as in Firefox.

// From service-worker.js:
const channel = new BroadcastChannel('sw-messages');
channel.postMessage({title: 'Hello from SW'});

// From your client pages:
const channel = new BroadcastChannel('sw-messages');
channel.addEventListener('message', event => {
  console.log('Received', event.data);
});