Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome ServiceWorker postMessage

I try to postMessage between a web application and the corresponding service worker. The service worker is successfully registered and working so far. Unfortunately, I noticed some strange behavior:

  1. The navigator.serviceWorker.controller is always null.
  2. At the service worker side, I implemented postMessage as follows:
self.addEventListener('message', function (evt) {
    console.log('postMessage received', evt);
});

Unfortunately, the important fields to post back to the origin evt.origin='' and evt.source=null do not contain the desired values. Nonetheless, I always received the sent evt.data.

Do you know how to post back?

Thank you very much!
Andi

like image 594
user24502 Avatar asked May 11 '15 21:05

user24502


People also ask

What is postMessage?

postMessage() is a safe way to send messages between windows in different domains or origins. One can also post to an IFrame. The data being sent is serialized using the structured clone algorithm and will accept almost any type of simple or complex data.

How do I use postMessage as a service worker?

The postMessage() method of the Client interface allows a service worker to send a message to a client (a Window , Worker , or SharedWorker ). The message is received in the " message " event on navigator. serviceWorker .


2 Answers

@GalBracha was asking if you could communicate with the client without first sending a message - yes!. Here's a quick example of how I did it when I wanted to send a message to clients when a push notification was received (not when the user clicked on the notification, but when the service worker received the event):

in your client js (after service worker registration, etc):

// navigator.serviceWorker.addEventListener('message', ... ) should work too
navigator.serviceWorker.onmessage = function (e) {
    // messages from service worker.
    console.log('e.data', e.data);
};

in your service worker, in response to some event (perhaps the install event):

// find the client(s) you want to send messages to:
self.clients.matchAll(/* search options */).then( (clients) => {
    if (clients && clients.length) {
        // you need to decide which clients you want to send the message to..
        const client = clients[0];
        client.postMessage("your message");
    }

the trick is (obviously?) to attach your listener for the message event to the serviceWorker object, not the window object.

like image 82
Allan Nienhuis Avatar answered Oct 23 '22 03:10

Allan Nienhuis


Broadcast Channel API is easier

Sending information back and forth between a service worker and its client is much easier using the Broadcast Channel API, compared to other methods.

Here is how broadcasting works

Define a new broadcasting channel in both the service worker and the client.

const channel4Broadcast = new BroadcastChannel('channel4');

To send a broadcast message in either the worker or the client:

channel4Broadcast.postMessage({key: value});

To receive a broadcast message in either the worker or the client:

channel4Broadcast.onmessage = (event) => {
    value = event.data.key;
}

Broadcasting also allows sending messages between web workers of the client, the client and the service worker.

Caveat

This simplicity comes at a price though. As it currently stands, the service worker will not wake up to receive broadcast messages. Therefore, it only works when the service worker is in a running (active or waiting) state; i.e. when the client is visible. Nonetheless, this may still be useful, for example to broadcast version numbers or web pushes, etc.

like image 24
Serge Stroobandt Avatar answered Oct 23 '22 05:10

Serge Stroobandt