Service Workers and postMessage Working Code

Theshagod
2 min readJan 16, 2021

Maybe it’s because I’m a noobie programmer looking in the wrong places, but it was just so hard for me to find an easy example that uses service workers with postMessage so that I could learn how to use them in my own project. I needed postMessage because I wanted to use the background sync feature of service workers and then re-render my DOM (in this case just the html) when my service workers finished background syncing. However, service workers cannot directly communicate with the DOM so we need to use something like postMessage to talk to the client side javascript. That javascript can use that information to update the DOM. After searching for a couple of hours, I finally stumbled across this example: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/message_event where I was able to get a postMessage working.

To setup postMessage with service workers you will need to create main.js, service-worker.js and index.html all in the root of your project.

This code goes into your main.js:

// paste the below code in your main.js// in the page being controlled
if (navigator.serviceWorker) {

navigator.serviceWorker.register('service-worker.js');

navigator.serviceWorker.addEventListener('message', event => {
// event is a MessageEvent object
console.log(`The service worker sent me a message: ${event.data}`);
});

navigator.serviceWorker.ready.then( registration => {
registration.active.postMessage("Hi service worker");
});

}

This goes into your service-worker.js:

// in the service worker
addEventListener('message', event => {
// event is an ExtendableMessageEvent object
console.log(`The client sent me a message: ${event.data}`);

event.source.postMessage("Hi client");
});

Your main will look like this:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body>Hi<script src= "main.js"></script></body></html>

You want to run this code with your chrome dev tools open. This can be achieved by right-clicking and clicking the inspect option. You should see console.log messages going which means that postMessage is working.

For my use case, I wanted to re-render the DOM after a background sync. At the end of my background sync an event occurs in my service-worker.js. I used postMessage to send a message to render the my DOM list. Here is what the code would look like:

service-worker.js:

var client;addEventListener('message', event => {   client = event.source;});/*sync code.........
*/
//.........
//end of background sync
someArbitraryEventThatOccursAtEndOfSync.oncomplete = event => { client.postMessage("renderList");}

main.js:

if (navigator.serviceWorker){      window.addEventListener('load', ()=> {      navigator.serviceWorker.register('/service-worker.js').then(() => {      return navigator.serviceWorker.ready      }).then(reg => {      //sending postMessage to client in service-worker.js         reg.active.postMessage("Hi service worker");      })   })   navigator.serviceWorker.addEventListener('message', event => {   // event is a MessageEvent object      if (event.data === "renderList"){         getAllEntries(db, data => {      if (data.length) renderList(data)      })      }   });}//more code below doing other things

We postMessage from the main.js initially to define client in service-worker.js. We are going to use client to make postMessages at the end of our events. When the end of the background sync occurs, main.js gets a postMessage of renderList which uses the custom functions that I built to update the list for my DOM.(I’m unsure if there is better way to get the client window object.)

Thanks for reading, I hope this helps someone.

--

--