Javascript 如何:ServiceWorker检查是否准备好更新

Javascript 如何:ServiceWorker检查是否准备好更新,javascript,service-worker,sw-precache,Javascript,Service Worker,Sw Precache,我正在努力实现的目标: 使用加载程序/微调器呈现页面 如果service worker.js已注册并处于活动状态,则检查更新 如果没有更新,则删除加载程序 如果updatefound并安装了新版本,则重新加载页面 else registerservice worker.js 当updatefound表示安装了新的加载程序时,请删除加载程序 我正在使用sw precache模块生成service worker.js和以下注册码: window.addEventListener('loa

我正在努力实现的目标:

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

  • 如果
    service worker.js
    已注册并处于活动状态,则检查更新

    • 如果没有更新,则删除加载程序
    • 如果
      updatefound
      并安装了新版本,则重新加载页面
  • else register
    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
检查
service worker.js
是否通过运行在内部进行了更改,但我看不到通过公共api公开的类似方法

我认为我的选择是:

  • 服务人员注册激活后等待几秒钟,查看是否触发了
    onUpdate-Found
  • 如果缓存未更新,则从
    service worker.js
    code触发自定义事件
还有其他建议吗?


编辑:

我提出了一些代码,通过在软件注册和软件客户端之间使用
postMessage()
解决了这个问题(正如@pate所建议的)

下面的演示试图在软件客户端和软件注册之间通过
postMessage
实现检查,但由于软件代码已被缓存而失败


编辑:

所以现在看来我无法实现我想要的,因为:

  • 当service worker处于活动状态时,您无法通过评估软件中的某些代码来检查更新-这仍然是相同的缓存软件,没有任何更改
  • 您需要等待
    onupdatefound
    ,没有其他任何东西会通知软件的更改
  • 旧软件的激活
    先于
    onupdatefound
  • 如果没有更改,则
    激活后不会触发任何内容
  • 软件注册不成熟,不断变化,
    从Chrome 46开始,update()返回一个承诺,如果操作成功完成或没有更新,该承诺将以“未定义”解决
  • 将超时设置为推迟视图渲染是次优的,因为没有明确的答案来确定应将其设置为多长时间,这也取决于软件大小

  • 我脑海中闪现的唯一方法是正常启动加载程序,然后在service worker的安装功能中将其删除。我将在您的service-worker.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();
        })
      );
    });
    

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

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

  • 在页面上注册onmessage处理程序
  • 从软件的激活或安装事件向页面发送消息
  • 当页面上收到消息时,相应地采取行动
  • 我自己将软件版本号保存在软件内部的一个变量中。然后,我的软件将该版本号发布到页面,页面已将其存储到浏览器的本地存储中。下一次加载页面时,SW将其当前版本号发布到页面,onmessage处理程序将其与当前存储的版本号进行比较。如果它们不相同,则软件已更新为mssage中包含的某个版本号。在那之后,我更新了版本号的localStorage副本,并做了这样那样的事情

    这个流程也可以通过另一种方式完成:从页面向软件发送消息,让软件回复一些信息,然后相应地采取行动


    我希望我能清楚地解释我的想法:)

    很好的建议,我用一个被黑客破解的解决方案做了一次尝试。现在我将等待更多的回复。是的,我并没有声称提供完整的程序,只是提供了概念。当我写removeLoader()时;在软件脚本中,我的意思是必须在那里做一些事情(一条消息?一个事件检查?)。一个警告是,如果软件还没有注册(第一次安装),它是可以的,但是如果它是,那么事件将从已经激活的软件中触发,并且它会说没有任何更改。因此,您似乎无法保证在收到这些信息后不会触发
    onUpdate-Found
    。看起来应该可以解决问题,但只有在工作人员发生更改时才会触发此事件。您好,您对此有任何更新吗?事实上,我没有,生产中的应用程序在初始加载(视图渲染)发生并随后检测到更改后会进行这种疯狂的刷新。谢谢您的回答