我正在我的网站上介绍服务工作者。我正在使用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消息,但他们不是该事件的注册监听器。所以我无法捕获数据。这是我的实施中的错误。
答案 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。不过,这可能是最重量级和最脆弱的方法。