service worker app-shell PHP 实现

service worker app-shell PHP implementation

我在我的 site.And 上引入了 service worker 我正在使用 app-shell 方法来响应 requests.Below 是我的代码结构。

serviceWorker.js

self.addEventListener("fetch", function(event) {
  if (requestUri.indexOf('-spid-') !== -1) {
    reponsePdPage(event,requestUri);
  }else{
    event.respondWith(fetch(requestUri,{mode: 'no-cors'}).catch(function (error){
        console.log("error in fetching => "+error);
        return new Response("not found");
        }) 
    );
  }
});


function reponsePdPage(event,requestUri){
   var appShellResponse=appShellPro();
   event.respondWith(appShellResponse);  //responds with app-shell
   event.waitUntil(
      apiResponse(requestUri)       //responds with dynamic content
   );
}

function appShellPro(){
   return fetch(app-shell.html);
}
function apiResponse(requestUri){
   var message=['price':'12.45cr'];
   self.clients.matchAll().then(function(clients){
    clients.forEach(function (client) {
        if(client.url == requestUri)
            client.postMessage(JSON.stringify(message));
    });
   });
}

应用-shell.html

<html>
  <head>
    <script>
            if ('serviceWorker' in navigator) {
              navigator.serviceWorker.onmessage = function (evt) {
                var message = JSON.parse(evt.data);
                document.getElementById('price').innerHTML=message['price'];
              }
            }
    </script>
  </head>
  <body>
      <div id="price"></div>
  </body>
</html>

serviceWorker.js 是我唯一的 service worker 文件。每当我在 url 中收到 -spid- 请求时,我都会调用 reponsePdPage function.In reponsePdPage 函数,我首先响应 app-shell.html。之后我调用 apiResponse 函数调用 post 消息并发送动态 data.The listener of post message写在app-shell.html.

我面临的问题是,有时 post 消息在侦听器 registration.It 之前被调用意味着 apiResponse 调用 post 消息但他们没有注册该事件的侦听器。所以我无法捕获数据。是他们在我的实现中出了什么问题吗?

我只关注最后一点,关于 service worker 和受控页面之间的通信。该问题与您提供的许多其他详细信息是分开的,例如使用 PHP 和采用 App Shell 模型。

如您所见,存在竞争条件,因为 service worker 中的代码和 HTML 的解析和执行是在不同的进程中执行的。当服务人员调用 client.postMessage().

时,onmessage 处理程序尚未在页面中建立,我对此并不感到惊讶。

如果您想将信息从 service worker 传递到受控页面,同时避免竞争条件,您有几个选择。

第一个可能也是最简单的选项是更改通信方向,并让受控页面使用 postMessage() 向 service worker 发送请求,然后 service worker 以相同的信息进行响应。如果您采用这种方法,您将确保受控页面已准备好接受 service worker 的响应。有一个完整的示例 here,但这里有一个相关位的简化版本,它使用基于 Promise 的包装器来处理从 service worker 收到的异步响应:

受控页面内:

function sendMessage(message) {
  // Return a promise that will eventually resolve with the response.
  return new Promise(function(resolve) {
    var messageChannel = new MessageChannel();
    messageChannel.port1.onmessage = function(event) {
      resolve(event.data);
    };

    navigator.serviceWorker.controller.postMessage(message,
      [messageChannel.port2]);
  });
}

Service Worker 内部:

self.addEventListener('message', function(event) {
  // Check event.data to see what the message was.
  // Put your response in responseMessage, then send it back:
  event.ports[0].postMessage(responseMessage);
});

其他方法包括在服务工作者内部的 IndexedDB 中设置一个值,然后在加载后从受控页面读取该值。

最后,您实际上可以获取从缓存存储 API 中检索到的 HTML,将其转换为字符串,修改该字符串以内嵌相关信息,然后响应包含修改后的 HTML 的新 Response。不过,这可能是最重量级和最脆弱的方法。