Как запустить отправленное сервером событие "только один раз" внутри 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.