如何:ServiceWorker 检查是否准备好更新 [英] How: ServiceWorker check if ready to update

查看:109
本文介绍了如何:ServiceWorker 检查是否准备好更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要实现的目标:

  • 使用加载器/微调器渲染页面

  • render page with loader/spinner

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

if service-worker.js is registered and active, then check for updates

  • 如果没有更新,则删除加载器
  • 如果安装了 updatefound 和新版本,则重新加载页面
  • if no updates, then remove loader
  • if updatefound and new version installed, then reload the page
  • updatefound,意味着安装了新的,移除加载器
  • when updatefound, meaning new one was installed, remove loader

我正在使用 sw-precache 模块来生成 service-worker.js 和以下注册代码:

I am using sw-precache module for me to generate service-worker.js and following registration code:

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 通过运行 get-newest-worker-algorithm,但我看不到通过公共 api 公开的类似方法.

After reading the spec it is clear that there are no handlers for something like updatenotfound. Looks like serviceWorker.register checks if service-worker.js changed internally by running get-newest-worker-algorithm, but I cannot see similar methods exposed via public api.

我认为我的选择是:

  • 在 Service Worker 注册激活后等待几秒钟,看看 onupdatefound 是否被触发
  • 如果缓存未更新,则从 service-worker.js 代码触发自定义事件
  • wait for couple of seconds after service worker registration becomes active to see if onupdatefound is fired
  • fire custom events from service-worker.js code if cache was not updated

还有其他建议吗?

我想出了一些代码来解决这个问题,方法是在软件注册和软件客户端之间使用 postMessage()(如@pate 建议的那样)

I've came up with some code which solves this issue by using postMessage() between SW registration and SW client (as @pate suggested)

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

Following demo tries to achieve checks through postMessage between SW client and SW registration, but fails as SW code is already cached DEMO

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

So by now it looks like I cannot implement what I want because:

  1. 当 Service Worker 处于活动状态时,您无法通过评估 SW 中的某些代码来检查更新 - 这仍然是相同的缓存 SW,没有任何更改
  2. 你需要等待onupdatefound,没有其他东西会通知软件的变化
  3. activation 旧软件的onupdatefound
  4. 如果没有变化,在激活
  5. 后什么也不会触发
  6. 软件注册 update() 不成熟,不断变化,从 Chrome 46 开始,update() 返回一个 promise,如果操作成功完成或没有更新,则返回一个 'undefined' 解析
  7. 设置超时以推迟视图渲染是次优的,因为对于应该设置多长时间没有明确的答案,这也取决于软件大小
  1. when service worker is active you cannot check for updates by evaluating some code in SW - this is still the same cached SW, no changes there
  2. you need to wait for onupdatefound, there is nothing else that will notify of changes in SW
  3. activation of older SW comes before onupdatefound
  4. if there is no change, nothing fires after activation
  5. SW registration update() is immature, keeps changing, Starting with Chrome 46, update() returns a promise that resolves with 'undefined' if the operation completed successfully or there was no update
  6. setting timeout to postpone view rendering is suboptimal as there is no clear answer to how long should it be set to, it depends on SW size as well

推荐答案

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

The other answer, provided by Fabio, doesn't work. The Service Worker script has no access to the DOM. It's not possible to remove anything from the DOM or, for instance, manipulate any data that is handling DOM elements from inside the Service Worker. That script runs separately with no shared state.

不过,您可以做的是在实际运行页面的 JS 和 Service Worker 之间发送消息.我不确定这是否是执行 OP 要求但可用于实现它的最佳方法.

What you can do, though, is send messages between the actual page-running JS and the Service Worker. I'm not sure if this is the best possible way to do what the OP is asking but can be used to achieve it.

  1. 在页面上注册一个 onmessage 处理程序
  2. 将来自软件的激活或安装事件的消息发送到页面
  3. 在页面上收到消息时采取相应的行动

我自己将软件版本号保存在软件内部的一个变量中.然后,我的软件将该版本号发布到页面,页面将其存储到浏览器的 localStorage 中.下次加载页面时,软件会将其当前版本号发布到页面,并且 onmessage 处理程序将其与当前存储的版本号进行比较.如果它们不相同,则软件已更新为包含在 mssage 中的某个版本号.在那之后,我更新了版本号的 localStorage 副本并完成了这个和那个.

I have myself kept SW version number in a variable inside the SW. My SW has then posted that version number to the page and the page has stored it into the localStorage of the browser. The next time the page is loaded SW posts it current version number to the page and the onmessage handler compares it to the currently stored version number. If they are not the same, then the SW has been updated to some version number that was included in the mssage. After that I've updated the localStorage copy of the version number and done this and that.

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

This flow could also be done in the other way around: send a message from the page to the SW and let SW answer something back, then act accordingly.

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

I hope I was able to explain my thoughts clearly :)

这篇关于如何:ServiceWorker 检查是否准备好更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆