Javascript “如何启动服务器发送事件”;“只有一次”;在SharedWorker内部为任何打开的脚本推送消息?

Javascript “如何启动服务器发送事件”;“只有一次”;在SharedWorker内部为任何打开的脚本推送消息?,javascript,jquery,addeventlistener,server-sent-events,shared-worker,Javascript,Jquery,Addeventlistener,Server Sent Events,Shared Worker,我有一个几乎没有问题的实现。我遇到的唯一问题是“一个用户可以与服务器建立多个连接”。基本上,如果用户打开多个web浏览器的选项卡,每个选项卡将创建一个全新的服务器发送事件请求到服务器,这将导致多个请求从单个用户运行 为了解决这个问题,我想在Javascript的内部运行SSE 这意味着我只有一个SSE与SharedWorker通信。然后,每个页面/web浏览器都将与共享工作人员通信。这给了我每个用户只允许一个SSE的优势 这就是我的SSE目前在没有任何类型工作人员的情况下的工作方式 $(func

我有一个几乎没有问题的实现。我遇到的唯一问题是“一个用户可以与服务器建立多个连接”。基本上,如果用户打开多个web浏览器的选项卡,每个选项卡将创建一个全新的服务器发送事件请求到服务器,这将导致多个请求从单个用户运行

为了解决这个问题,我想在Javascript的内部运行SSE

这意味着我只有一个SSE与SharedWorker通信。然后,每个页面/web浏览器都将与共享工作人员通信。这给了我每个用户只允许一个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();
        };

    }
});
我希望运行相同的设置。但是,我希望在javascript的SharedWorker中运行它,以消除每个用户拥有多个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);
    }
}

可能很晚,但您可以在worker中创建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/#workers.

我真的不想把这称为
…轮询
-SSE是一种推送技术:-)那么你到底有什么问题?什么不起作用,有什么错误吗?什么是
processServerData
?您是否曾经将工作人员的消息发布到连接的页面?嗯,您确实不应该在工作人员的
onconnect
处理程序中创建
新事件源(icwsPollingUrl)
,这只会再次为每个连接的网页创建一个事件源。@Bergi那么我在哪里创建连接呢?
processServerData
功能读取SSE发送的消息,并对其进行处理“在屏幕上显示不同的消息”我正在尝试实施推送技术,其中一条消息被读取并推送到任何打开的浏览器
onconnect
在您的工作人员连接到推送服务时不被调用,但当网页确实连接到您的工作人员时。您将只希望在工作程序本身(启动)中创建一次新的事件源。
            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);