如何:服务工作者检查是否准备好更新



我想要实现的目标:

  • 使用加载器/微调器的呈现页面

  • 如果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实现检查,但由于软件代码已缓存而失败 演示


编辑:

所以到目前为止,看起来我无法实现我想要的东西,因为:

  1. 当 Service worker 处于活动状态时,您无法通过评估 SW 中的某些代码来检查更新 - 这仍然是相同的缓存软件,没有更改
  2. 您需要等待onupdatefound,没有其他任何东西可以通知软件的变化
  3. activation较旧的软件先于onupdatefound
  4. 如果没有变化,则activation后不会触发任何内容
  5. 软件注册update()不成熟,不断变化,Starting with Chrome 46, update() returns a promise that resolves with 'undefined' if the operation completed successfully or there was no update
  6. 设置
  7. 超时以推迟视图渲染是次优的,因为对于应该设置多长时间没有明确的答案,它也取决于软件大小

法比奥提供的另一个答案不起作用。服务工作进程脚本无权访问 DOM。例如,不可能从 DOM 中删除任何内容,或者从Service Worker 内部操作处理 DOM 元素的任何数据。该脚本单独运行,没有共享状态。

但是,您可以做的是在实际运行页面的 JS 和服务工作线程之间发送消息。我不确定这是否是完成 OP 要求的最佳方法,但可以用来实现它。

  1. 在页面上注册消息处理程序
  2. 从软件的激活或安装事件向页面发送消息
  3. 在页面上收到消息时采取相应措施

我自己将 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();
})
);
});

相关内容

  • 没有找到相关文章

最新更新