服务工作者app-shell PHP实现

时间:2016-12-14 10:49:44

标签: javascript service-worker postmessage progressive-web-apps

我正在我的网站上介绍服务工作者。我正在使用app-shell方法来响应请求。我是我的代码结构。

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 是我唯一的服务工作者文件。每当我收到-spid- in url的请求时,我都会调用 reponsePdPage function.In reponsePdPage函数我首先回复 app-shell.html 。之后我正在调用 apiResponse 函数调用postmessage并发送动态数据。发布消息监听器写在 app中-shell.html

我面临的问题是,有时在收听者注册之前调用邮件消息。这意味着 apiResponse 调用post消息,但他们不是该事件的注册监听器。所以我无法捕获数据。这是我的实施中的错误。

1 个答案:

答案 0 :(得分:2)

我将专注于最后一点,关于服务工作者和受控页面之间的通信。该问题与您提供的许多其他细节分开,例如使用PHP并采用App Shell模型。

正如您所观察到的那样,由于服务工作者中的代码以及HTML的解析和执行是在单独的进程中执行的,因此存在竞争条件。在服务工作者调用onmessage时,页面中尚未建立client.postMessage()处理程序,我并不感到惊讶。

如果您想将服务工作者的信息传递给受控页面,您可以选择一些选项,同时避免竞争条件。

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

在受控页面内:

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

服务工作者内部:

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中的值,然后在加载后从受控页面读取。

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