Как запустить отправленное сервером событие "только один раз" внутри SharedWorker, чтобы отправить сообщение для любого открытого скрипта?

У меня есть реализация отправленного сервером события (SSE), которая работает практически без проблем. Единственная проблема, с которой я сталкиваюсь, это "у одного пользователя может быть много подключений к серверу". По сути, если пользователь открывает более одной вкладки веб-браузера, каждая вкладка создает новый отправленный сервером запрос о событии на сервер, который вызывает много запросов от одного пользователя.

Чтобы решить эту проблему, я хотел бы запустить SSE внутри SharedWorker Javascript.

Это означает, что у меня есть только один SSE, взаимодействующий с SharedWorker. Затем каждая страница / веб-браузер будет взаимодействовать с SharedWorker. Это дает мне преимущество, позволяя использовать только один SSE для каждого пользователя.

Так работает мой SSE без какого-либо работника.

$(function(){
    //connect to the server to read messages
    $(window).load(function(){
        startPolling( new EventSource("poll.php") );
    });

    //function to listen for new messages from the server
    function startPolling(evtSource){

        evtSource.addEventListener("getMessagingQueue", function(e) {
            var data = JSON.parse(e.data);
            //handle recieved messages
            processServerData(data);

        }, false);

        evtSource.onerror = function(e) {
            evtSource.close();
        };

    }
});

Я хотел бы иметь ту же настройку. Тем не менее, я хотел бы запустить его внутри SharedWorker javascript, чтобы исключить наличие более одного SSE на пользователя.

Я изо всех сил пытаюсь реализовать SharedWorker. Вот что я пробовал до сих пор

Я создал файл с именем worker.js и добавил этот код к нему

var ports = [] ;

onconnect = function(event) {

    var port = event.ports[0];
    ports.push(port);
    port.start();

    var serv = new EventSource(icwsPollingUrl) 
    serv.addEventListener("getMessagingQueue", function(e) {
        var data = JSON.parse(e.data);
        processServerData(data);

    }, false);

}

Затем на странице, где я хочу, чтобы в списке сообщений у меня есть этот код

$(function(){

    $(window).load(function(){

        var worker = new SharedWorker("worker.js");         


         worker.port.start();
         worker.port.onmessage = function(e) {
            console.log(e.data);
            console.log('Message received from worker');
         }

    });
});

Что мне здесь не хватает?

Что я делаю неправильно?

Как я могу исправить реализацию?

РЕДАКТИРОВАНИЕ

Основываясь на комментариях ниже @Bergi, вот обновленная версия моей реализации, которая до сих пор не отправляет сообщения на соединители. Я добавил комментарии к своему коду, объясняющие понимание того, что происходит с кодом.

На целевой странице т.е. index.php Я подключаюсь к своему SharedWorker следующим образом

$(function($){

    //establish connection to the shared worker
    var worker = new SharedWorker("/add-ons/icws/js/worker1.js");
        //listen for a message send from the worker
        worker.port.addEventListener("message",
                function(event) {
                    console.log(event.data);
                }
                , false
        );
        //start the connection to the shared worker
        worker.port.start();

 });

Это код как мой worker1.js файл содержит

var ports = [] ;

//runs only when a new connection starts
onconnect = function(event) {

    var port = event.ports[0];
    ports.push(port);
    port.start();

    //implement a channel for a communication between the connecter and the SharedWorker
    port.addEventListener("message",
        function(event) { 
            listenForMessage(event, port);
        }
    );
}

//reply to any message sent to the SharedWorker with the same message but add the phrase "SharedWorker Said: " to it
listenForMessage = function (event, port) {
    port.postMessage("SharedWorker Said: " + event.data);

}

//runs every time and post the message to all the connected ports
function readNewMessages(){
    var serv = new EventSource(icwsPollingUrl) 
        serv.addEventListener("getMessagingQueue", function(e) {
        var queue = JSON.parse(e.data);

        notifyAllPorts(queue);

    }, false);
}

//check all open ports and post a message to each
function notifyAllPorts(msg){
    for(i = 0; i < ports.length; i++) {
        ports[i].postMessage(msg);
    }
}

Вот еще одна версия моей worker1.js

var ports = [] ;

//runs only when a new connection starts
onconnect = function(event) {

    var port = event.ports[0];
    ports.push(port);
    port.start();

    //implement a channel for a communication between the connecter and the SharedWorker
    port.addEventListener("message",
        function(event) { 
            listenForMessage(event, port);
        }
    );
}

//reply to any message sent to the SharedWorker with the same message but add the phrase "SharedWorker Said: " to it
listenForMessage = function (event, port) {
    port.postMessage("SharedWorker Said: " + event.data);

}

readNewMessages();


//runs every time and post the message to all the connected ports
function readNewMessages(){
    console.log('Start Reading...');
    var serv = new EventSource(icwsPollingUrl);
        serv.addEventListener("getMessagingQueue", function(e) {
        var queue = JSON.parse(e.data);
        console.log('Message Received');
        console.log(queue);

        notifyAllPorts(queue);

    }, false);
}

//check all open ports and post a message to each
function notifyAllPorts(msg){
    for(i = 0; i < ports.length; i++) {
        ports[i].postMessage(msg);
    }
}

0 ответов

Возможно , опаздывает, но вы можете создать синглтон EventSource в работнике следующим образом:

let ports = [];
var EventSourceSingleton = (function () {
    var instance;

    function createInstance() {
        var object = new EventSource('your path');
        return object;
    }

    return {
        getInstance: function () {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();

onconnect = function(e) {
    var port = e.ports[0];
    ports.push(port);
    var notifyAll = function(message){
        ports.forEach(port => port.postMessage(message));
    }

    var makeConnection = function (){
        var source = EventSourceSingleton.getInstance();

        source.onopen = function (e){
            var message = "Connection open"
            port.postMessage(message);
        }
        source.onerror = function(e){
            var message ="Ups you have an error";
            port.postMessage(message);
        }
        source.onmessage = function(e){
            // var message = JSON.parse(event.data);
            notifyAll(e.data);
        }
    }

    port.onmessage = function(e) {
        makeConnection();
    }
    port.start();
  }

И вы можете назвать это со стороны вот так.

            var shWorker = new SharedWorker('woker.js');

            shWorker.port.onmessage = function (e) {
                console.log('Message received from worker');
                setmsj(e.data);
            }
            //Dummy message - For initialize
            shWorker.port.postMessage(true);

Удачи, отладьте это на // chrome://inspect/#worker.

Другие вопросы по тегам