我想要实现的目标:
-
使用加载器/微调器的呈现页面
-
如果
service-worker.js
已注册并处于活动状态,请检查更新- 如果没有更新,则删除加载程序
- 如果安装了
updatefound
新版本,则重新加载页面
- 否则注册
service-worker.js
- 当
updatefound
时,意味着安装了新的,删除加载程序
- 当
我正在使用sw-precache
模块来生成service-worker.js
和以下注册码:
window.addEventListener('load', function() {
// show loader
addLoader();
navigator.serviceWorker.register('service-worker.js')
.then(function(swRegistration) {
// react to changes in `service-worker.js`
swRegistration.onupdatefound = function() {
var installingWorker = swRegistration.installing;
installingWorker.onstatechange = function() {
if(installingWorker.state === 'installed' && navigator.serviceWorker.controller){
// updated content installed
window.location.reload();
} else if (installingWorker.state === 'installed'){
// new sw registered and content cached
removeLoader();
}
};
}
if(swRegistration.active){
// here I know that `service-worker.js` was already installed
// but not sure it there are changes
// If there are no changes it is the last thing I can check
// AFAIK no events are fired afterwards
}
})
.catch(function(e) {
console.error('Error during service worker registration:', e);
});
});
阅读规范后,很明显没有类似updatenotfound
之类的处理程序。看起来serviceWorker.register
通过运行最新的worker算法来检查service-worker.js
内部是否发生了变化,但我看不到通过公共API公开的类似方法。
我认为我的选择是:
- 在服务工作进程注册变为活动状态后等待几秒钟,以查看是否触发了
onupdatefound
如果未更新缓存,则从service-worker.js
代码触发自定义事件
还有其他建议吗?
编辑:
我想出了一些代码,通过在软件注册和软件客户端之间使用postMessage()
来解决此问题(如@pate建议的那样(
以下演示尝试通过软件客户端和软件注册之间的postMessage
实现检查,但由于软件代码已缓存而失败 演示
编辑:
所以到目前为止,看起来我无法实现我想要的东西,因为:
- 当 Service worker 处于活动状态时,您无法通过评估 SW 中的某些代码来检查更新 - 这仍然是相同的缓存软件,没有更改
- 您需要等待
onupdatefound
,没有其他任何东西可以通知软件的变化 activation
较旧的软件先于onupdatefound
- 如果没有变化,则
activation
后不会触发任何内容 - 软件注册
update()
不成熟,不断变化,Starting with Chrome 46, update() returns a promise that resolves with 'undefined' if the operation completed successfully or there was no update
设置 - 超时以推迟视图渲染是次优的,因为对于应该设置多长时间没有明确的答案,它也取决于软件大小
法比奥提供的另一个答案不起作用。服务工作进程脚本无权访问 DOM。例如,不可能从 DOM 中删除任何内容,或者从Service Worker 内部操作处理 DOM 元素的任何数据。该脚本单独运行,没有共享状态。
但是,您可以做的是在实际运行页面的 JS 和服务工作线程之间发送消息。我不确定这是否是完成 OP 要求的最佳方法,但可以用来实现它。
- 在页面上注册消息处理程序
- 从软件的激活或安装事件向页面发送消息
- 在页面上收到消息时采取相应措施
我自己将 SW 版本号保存在 SW 内部的变量中。然后,我的软件将该版本号发布到页面上,并且该页面已将其存储到浏览器的本地存储中。下次加载页面时,SW 会将其当前版本号发布到页面,onmessage 处理程序会将其与当前存储的版本号进行比较。如果它们不同,则软件已更新为 mssage 中包含的某个版本号。之后,我更新了版本号的本地存储副本并完成了这个和那个。
此流程也可以以相反的方式完成:从页面向 SW 发送消息,让 SW 回复一些内容,然后采取相应的行动。
我希望我能够清楚地解释我的想法:)
我脑海中浮现的唯一方法是正常启动加载程序,然后在服务工作者的安装功能中删除它。我会在你的服务工作者中尝试一下.js:
self.addEventListener('install', function(e) {
console.log('[ServiceWorker] Install');
e.waitUntil(
caches.open(cacheName).then(function(cache) {
console.log('[ServiceWorker] Caching app shell');
return cache.addAll(filesToCache);
}).then(function() {
***removeLoader();***
return self.skipWaiting();
})
);
});