Comment rendre EventSource disponible dans SharedWorker dans FireFox?

J'essaie d'implémenter des événements envoyés par le serveur (SSE) dans un SharedWorker.

La mise en œuvre fonctionne sans problème dans Google Chrome. Cependant, il ne fonctionne pas dans FireFox.

Lorsque j'essaie de le faire fonctionner dans FireFox, je reçois cette erreur dans la console.

error { target: SharedWorker, isTrusted: true, message: "ReferenceError: EventSource is not defined", filename: "https://example.com/add-ons/icws/js/worker.js", lineno: 28, colno: 0, currentTarget: SharedWorker, eventPhase: 2, bubbles: false, cancelable: true, defaultPrevented: false } 

Comment puis-je créer EventSource dans le SharedWorker ?

C'est ainsi que SharedWorker la SharedWorker the SharedWorker

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

C'est mon script de travail

 var clients = new Array(); readNewMessages(); //runs only when a new connection starts onconnect = function(event) { var port = event.ports[0]; clients.push(port); port.start(); //implement a channel for a communication between the connecter and the SharedWorker port.addEventListener("message", function(event) { replyToClientMessage(event, port); } , false ); } //reply to any message sent to the SharedWorker replyToClientMessage = function (event, port) { port.postMessage(event.data); } //runs every time and post the message to all the connected client function readNewMessages(){ var serv = new EventSource('/add-ons/icws/poll.php'); serv.addEventListener("getMessagingQueue", function(event) { var queue = JSON.parse(event.data); notifyAllPorts(queue); }, false); } //check all open clients and post a message to each function notifyAllPorts(msg){ var len = clients.length; var port; for(i = 0; i < len; i++) { port = clients[i]; port.postMessage(msg); } } 

Lors de la recherche d'une solution, j'ai appris que EventSource ne fait pas partie de SharedWorkerGlobalScope

J'ai essayé de changer mon code de travail à ce sujet, mais cela ne fonctionnait pas toujours

 var serv = new self.EventSource('/add-ons/icws/poll.php'); var clients = new Array(); readNewMessages(); //runs only when a new connection starts onconnect = function(event) { var port = event.ports[0]; clients.push(port); port.start(); //implement a channel for a communication between the connecter and the SharedWorker port.addEventListener("message", function(event) { replyToClientMessage(event, port); } , false ); } //reply to any message sent to the SharedWorker with the same message but add the phrase "SharedWorker Said: " to it replyToClientMessage = function (event, port) { port.postMessage(event.data); } //runs every time and post the message to all the connected client function readNewMessages(){ serv.addEventListener("getMessagingQueue", function(event) { var queue = JSON.parse(event.data); notifyAllPorts(queue); }, false); } //check all open clients and post a message to each function notifyAllPorts(msg){ var len = clients.length; var port; for(i = 0; i < len; i++) { port = clients[i]; port.postMessage(msg); } } 

Comment résoudre ce problème?

Pourquoi FF vous permettrait d'avoir un WebSocket dans un Worker mais pas un EventSource Je ne suis pas sûr, mais il vous donne tous les outils pour créer un bon polyfill (collez-le dans le haut de votre script SharedWorker):

 //FF only; some missing functionality, but handles the essentials //most of what's missing can be added if you have the motivation (function(global) { if ('EventSource' in global) return; function EventSource(url) { if (!(this instanceof EventSource)) return new EventSource(url); this.url = url; var self = this; var listeners = {}; self.addEventListener = function(type, handler) { if (!listeners[type]) { listeners[type] = new Set(); } listeners[type].add(handler); }; self.removeEventListener = function(type, handler) { if (listeners[type]) { listeners[type].delete(handler); } }; self.dispatchEvent = function(event) { if (listeners[event.type]) { listeners[event.type].forEach(function(handler) { setTimeout(function() { switch (typeof(handler)) { case 'object': handler.handleEvent(event); break; case 'function': handler(event); break; } }); }); } if (typeof(self['on' + event.type.toLowerCase()]) == 'function') { setTimeout(function() { self['on' + event.type.toLowerCase()](event); }); } }; var buffer = ''; //if you want to handle other prefixes, you'll need to tweak these var msgRE = /^(?:data: .*\n)*\n/; var dataRE = /^data: (.*)$/; function _parse() { while (msgRE.test(buffer)) { var msg = msgRE.exec(buffer)[0]; //msg now contains a single raw message var data = null; var lines = msg.split("\n").slice(0, -2); //remove last 2 newlines if (lines.length) { data = ''; lines.forEach(function(line) { data += dataRE.exec(line)[1]; }); } var event = new MessageEvent('message', { 'data' : data, 'origin' : url }); self.dispatchEvent(event); buffer = buffer.substr(msg.length); } } var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'moz-chunked-text'; //FF only xhr.setRequestHeader('Accept', 'text/event-stream'); xhr.onprogress = function() { if (xhr.response !== null) { buffer += xhr.response; } _parse(); }; xhr.onreadystatechange = function() { switch (xhr.readyState) { case XMLHttpRequest.HEADERS_RECEIVED: if (xhr.status == 200) { self.readyState = EventSource.OPEN; break; } //else console.error("EventSource: " + url + " = " + xhr.statusText); //fallthrough case XMLHttpRequest.DONE: self.readyState = EventSource.CLOSED; break; default: break; } }; xhr.send(); Object.defineProperty(this, 'close', { 'value' : function() { xhr.abort(); }}); return this; } Object.defineProperties(EventSource, { 'CONNECTING' : { 'value' : 0, 'enumerable' : true }, 'OPEN' : { 'value' : 1, 'enumerable' : true }, 'CLOSED' : { 'value' : 2, 'enumerable' : true }, }); EventSource.prototype = Object.create(EventTarget.prototype); Object.defineProperties(EventSource.prototype, { 'constructor' : { 'value' : EventSource }, 'readyState' : { 'value' : 0, 'writable' : true, 'enumerable' : true }, 'withCredentials' : { 'value' : false, 'enumerable' : true }, //not supported 'onopen' : { 'writable' : true }, 'onmessage' : { 'writable' : true }, 'onerror' : { 'writable' : true }, 'close' : { 'value' : function() { }, 'configurable' : true, 'enumerable' : true } }); global.EventSource = EventSource; })(this); 

Vous pouvez trouver des polyfills plus complets ici et ici . J'avais besoin d'un système qui fonctionne avec un flux non enregistré en temps réel (si vous n'êtes pas connecté au flux lorsque l'événement se produit, il est parti); C'est ce que j'ai proposé. La principale différence est le type de réponse au texte moz-chunked, qui vous donne accès aux flux non codés dans l'événement de progression. Prendre plaisir 😉