首页 文章

服务工作者在从另一个工作人员获取数据后响应获取

提问于
浏览
1

我正在使用服务工作者拦截对我的请求,并通过与Web工作者(也是从同一父页面创建)进行通信来提供对获取请求的响应 . 我已经使用消息通道在工作者和服务工作者之间进行直接通信 . 这是我写的一个简单的POC:

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});
    }));
});

港口的角色:

otherPort :与 Worker 沟通

parentPort :与父页面通信

在 Worker 中,我有一个数据库说:

var dataBase = {
    "file1.txt": "This is File1",
    "file2.txt": "This is File2"
};

工作人员只根据服务工作人员发送的密钥提供正确的数据 . 实际上这些将是非常大的文件 .

我面临的问题如下:

  • 由于我使用的是全局dummyObj,因此旧的dummyObj以及旧的onmessage丢失,只有最新的资源被接收到的数据响应 .

  • 实际上,file2获取 This is File1 ,因为最新的dummyObj用于file2.txt,但是worker首先发送file1.txt的数据 .

我尝试直接创建一个iframe,并拦截其中的所有请求:

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

这是我得到的输出:

一种方法是在创建iframe之前编写可以在worker中的IndexedDB中获取的所有文件 . 然后在Service Worker中从索引的DB中获取它们 . 但我不想保存IDB中的所有资源 . 所以这种方法不是我想要的 .

有没有人知道如何以其他方式完成我想要做的事情?或者我正在做什么修复 .

请帮忙!

UPDATE

我通过在全局队列中排队dummyObjs而不是拥有全局对象来实现这一点 . 并且在 msgFromW 收到工作者的响应时,我从队列中弹出一个元素并调用它的 callHandler 函数 . 但我不确定这是否是一个可靠的解决方案 . 因为它假设一切都将按顺序发生 . Is this assumption correct?

1 回答

  • 0

    我建议在promises中将服务工作者和Web worker之间传递的消息包装起来,然后将使用Web worker的数据解析的promise传递给 fetchEvent.respondWith() .

    promise-worker库可以为您自动执行此承诺包装,或者您可以手动执行,使用this example作为指南 .

    如果您使用 promise-worker ,您的代码将类似于:

    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 */));
      }
    });
    

相关问题