1
votes

I have a simple service worker which, on fetch, posts a message to the client:

// main.js

navigator.serviceWorker.register("./service-worker.js");

console.log("client: addEventListener message");
navigator.serviceWorker.addEventListener("message", event => {
  console.log("client: message received", event.data);
});
<script src="main.js"></script>
// service-worker.js

self.addEventListener("fetch", event => {
  console.log("service worker: fetch event");

  event.waitUntil(
    (async () => {
      const clientId =
        event.resultingClientId !== ""
          ? event.resultingClientId
          : event.clientId;
      const client = await self.clients.get(clientId);

      console.log("service worker: postMessage");
      client.postMessage("test");
    })()
  );
});

When I look at the console logs, it's clear that the message event listener is registered after the message is posted by the service worker. Nonetheless, the event listener still receives the message.

enter image description here

I suspect this is because messages are scheduled asynchronously:

postMessage() schedules the MessageEvent to be dispatched only after all pending execution contexts have finished. For example, if postMessage() is invoked in an event handler, that event handler will run to completion, as will any remaining handlers for that same event, before the MessageEvent is dispatched.

https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Notes

However, I'm not sure what this means in this specific example. For example, when the fetch event handler has ran to completion, is the client JavaScript guaranteed to have ran, and therefore the message event listener will be registered?

I have a larger app that is doing something similar to the above, but the client JavaScript is ran slightly later in the page load, so I would like to know when exactly the event listener must be registered in order to avoid race conditions and guarantee the message posted by the service worker will be received.

1

1 Answers

1
votes

By default, all messages sent from a page's controlling service worker to the page (using Client.postMessage()) are queued while the page is loading, and get dispatched once the page's HTML document has been loaded and parsed (i.e. after the DOMContentLoaded event fires). It's possible to start dispatching these messages earlier by calling ServiceWorkerContainer.startMessages(), for example if you've invoked a message handler using EventTarget.addEventListener() before the page has finished loading, but want to start processing the messages right away.

https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/startMessages