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 syncsomeArbitraryEventThatOccursAtEndOfSync.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.