0

Ich verwende Service-Mitarbeiter, um Anfragen für mich abzufangen und die Antworten auf die Abrufanforderungen durch Kommunikation mit einem Web-Worker (ebenfalls von der gleichen übergeordneten Seite) bereitzustellen. Ich habe Nachrichtenkanäle für die direkte Kommunikation zwischen dem Arbeiter und Service-Arbeiter verwendet. Hier ist ein einfaches POC ich geschrieben habe:Service Worker reagiert auf Abruf nach dem Abrufen von Daten von einem anderen Mitarbeiter

var otherPort, parentPort; 
var dummyObj; 

var DummyHandler = function() 
{ 
    this.onmessage = null; 
    var selfRef = this; 

    this.callHandler = function(arg) 
    { 
     if (typeof selfRef.onmessage === "function") 
     { 
      selfRef.onmessage(arg); 
     } 
     else 
     { 
      console.error("Message Handler not set"); 
     } 
    }; 
}; 

function msgFromW(evt) 
{ 
    console.log(evt.data); 
    dummyObj.callHandler(evt); 
} 

self.addEventListener("message", function(evt) { 
    var data = evt.data; 
    if(data.msg === "connect") 
    { 
     otherPort = evt.ports[1]; 
     otherPort.onmessage = msgFromW; 
     parentPort = evt.ports[0]; 
     parentPort.postMessage({"msg": "connect"}); 
    } 
}); 

self.addEventListener("fetch", function(event) 
{ 
    var url = event.request.url; 
    var urlObj = new URL(url); 
    if(!isToBeIntercepted(url)) 
    { 
     return fetch(event.request); 
    } 
    url = decodeURI(url); 

    var key = processURL(url).toLowerCase(); 
    console.log("Fetch For: " + key); 

    event.respondWith(new Promise(function(resolve, reject){ 
     dummyObj = new DummyHandler(); 
     dummyObj.onmessage = function(e) 
     { 
      if(e.data.error) 
      { 
       reject(e.data.error); 
      } 
      else 
      { 
       var content = e.data.data; 
       var blob = new Blob([content]); 
       resolve(new Response(blob)); 
      } 
     }; 

     otherPort.postMessage({"msg": "content", param: key}); 
    })); 
}); 

Rollen der Ports:

anderer_Port: Kommunikation mit Arbeiter

parentPort: Kommunikation mit übergeordneten Seite

In der Arbeiter, ich habe eine Datenbank sagen:

Der Mitarbeiter liefert nur die korrekten Daten entsprechend dem vom Service-Mitarbeiter gesendeten Schlüssel. In Wirklichkeit werden dies sehr große Dateien sein.

Das Problem, das ich mit dieser bin vor ist die folgende:

  1. Da ich eine globale dummyObj verwenden, die ältere dummyObj und damit die ältere onmessage verloren geht und nur die letzte Ressource wird mit den empfangenen Daten reagiert .
  2. Tatsächlich erhält Datei2 This is File1, weil das letzte dummyObj für file2.txt ist, aber der Arbeiter zuerst Daten für file1.txt sendet.

Ich habe versucht, durch ein iframe direkt erstellen und alle Anforderungen in ihm abgefangen werden:

<html> 
<head></head> 
<body><iframe src="tointercept/file1.txt" ></iframe><iframe src="tointercept/file2.txt"></iframe> 
</body> 
</html> 

Hier ist, was ich als Ausgabe erhalten: enter image description here

Ein Ansatz alle schreiben könnte die Dateien, die vor dem Erstellen des Iframes in den Worker in IndexedDB abgerufen werden konnten. Dann im Service Worker die aus der indizierten DB holen. Aber ich möchte nicht alle Ressourcen in IDB speichern. Also dieser Ansatz ist nicht was ich will.

Kennt jemand einen Weg, um zu erreichen, was ich auf eine andere Weise versuche? Oder gibt es eine Lösung für das, was ich tue?

Bitte Hilfe!

UPDATE

Ich habe dies durch die Warteschlangen dummyObjs in einer globalen Warteschlange stattdessen ein globales Objekt mit der Arbeit bekam. Und wenn ich die Antwort vom Arbeiter in msgFromW empfange, knalle ich ein Element aus der Warteschlange und rufe seine callHandler Funktion auf. Aber ich bin mir nicht sicher, ob dies eine zuverlässige Lösung ist. Da es annimmt, dass alles in der Reihenfolge auftreten wird. Ist diese Annahme richtig?

Antwort

-1

Ich würde empfehlen, Ihre Nachricht zwischen dem Service-Mitarbeiter und dem Web-Arbeiter in Versprechen zu übergeben und dann ein Versprechen zu übergeben, das mit den Daten vom Web-Arbeiter zu fetchEvent.respondWith() löst.

Die Bibliothek promise-worker kann diese Verpackung für Sie automatisieren, oder Sie können es manuell durchführen, indem Sie this example als Richtlinie verwenden.

Wenn Sie promise-worker verwenden, würden Sie den Code in etwa so aussehen:

var promiseWorker = new PromiseWorker(/* your web worker */); 

self.addEventListener('fetch', function(fetchEvent) { 
    if (/* some optional check to see if you want to handle this event */) { 
    fetchEvent.respondWith(promiseWorker.postMessage(/* file name */)); 
    } 
}); 
+0

Wenn Sie meinen Code zu sehen, nicht ich das Gleiche getan? – tapananand

+0

Sie verwenden Versprechungen, aber eine globale Warteschlange, die außerhalb der Nachrichtenrückrufe verwaltet wird, sollte nicht benötigt werden. Sie können sich auf Versprechungen verlassen, die auf den spezifischen Rückruf ausgerichtet sind. –

+0

Ich verwende Versprechungen, aber ich rufe die Meldung von dummyobj manuell auf Antwort vom Arbeiter. Also brauche ich die Queue/Map, um zu verfolgen, wessen on-Nachricht zu rufen – tapananand