Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transfer data between client and serviceWorker

I want to try run websockets in serviceWorker.

I write code for register serviceWorker:

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register(
            GetDataForUser.settings.service_worker + "?version=" + GetDataForUser.settings.service_worker_version,
            {scope: './'}
        )
        .then(() => navigator.serviceWorker
            .ready
            .then((worker) => {
        console.log(worker);
                worker.sync.register('syncdata');
            })
        )
        .catch((err) => console.log(err));
    navigator.serviceWorker.addEventListener('message', event => {
        console.log('++++++++++++++++++++', event.data.msg, event.data.url);
    });
}

And write serviceWorker code:

var ws = null;

self.addEventListener('install', (event) => {
    console.log('Install');
});

self.addEventListener('activate', (event) => {
    console.log('Activate');

    ws = new WebSocket('ws://local.ll:8880');

    ws.onopen = function() {
        console.log("Open");
    };

    // On message receive
    ws.onmessage = function (event) {
        console.log("Message receive " + event.data);
        console.log(event);
        event.ports[0].postMessage({'test': 'This is my response.'});
    };

    // On error connection
    ws.onerror = function (error) {
        console.log("Error " + error.message);
    };

    // On close connection
    ws.onclose = function (event) {
        if (event.wasClean) {
            console.log('clean closed');

        } else {
            console.log('broken connection');
        }
        console.log('Code: ' + event.code + ' reason: ' + event.reason);
    };
});

self.addEventListener('fetch', (event) => {});

self.addEventListener('message', function (evt) {
    console.log('postMessage received', evt.data);
    ws.send('121212');
});

I try to send data to serviceWorker next:

navigator.serviceWorker.controller.postMessage({'hello': 'world'});

But receive an error:

Uncaught TypeError: Cannot read property 'postMessage' of null

console.log(navigator.serviceWorker);
ServiceWorkerContainer {controller: null, ready: Promise, oncontrollerchange: null, onmessage: null}

Trying to send message from serviceWorker to client next:

event.ports[0].postMessage({'test': 'This is my response.'});

But event.ports is empty.

Whats wrong? How to transfer data between client and serviceWorker.

like image 533
user2264941 Avatar asked Sep 17 '25 05:09

user2264941


1 Answers

To fix your error of controller being null, you need to add the activate event listener

self.clients.claim()

Without that, when the service worker is activated, the page is not controlled by it until the next navigation. This allows the service worker to take control of the pages as soon as it's active.

But I don't think it's your only problem. Looking at your code I think you're confusing WebSocket and MessageChannel. You seem to try to use WebSocket to send messages between client and service worker where you should be using MessageChannel for that.

For exemple if we want to send messages from the client to the SW and allow the SW to respond to those messages, we create a MessageChannel, and we send a port of this channel allong with the message for the SW to use in his response. in the client :

var msg = new MessageChannel();
msg.port1.onmessage = function(event){
    //Response received from SW
    console.log(event.data);
};
// Send message to SW
navigator.serviceWorker.controller.postMessage("hello", [msg_chan.port2]);

in the SW :

self.addEventListener('message', function(event){
    //Message received from client
    console.log(event.data);
    //Send response to client using the port that was sent with the message
    event.ports[0].postMessage("world");
});
like image 173
J.Loscos Avatar answered Sep 18 '25 19:09

J.Loscos