【问题标题】:Service Worker sometimes installs without waitingService Worker 有时无需等待即可安装
【发布时间】:2021-05-07 20:17:32
【问题描述】:

我在我的 Angular 应用程序中使用 Workbox,我每 15 分钟检查一次更新,以便通知用户是否已部署新版本。

找到更新后,新的 Service Worker 已安装但未激活,因为此时我可以提示用户重新加载页面:

点击 OK 后,我可以通知我的 SW 跳过等待,因为他有这个 EventListener:

addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING') {
    skipWaiting();
  }
});

这很好用,但有时(我还没有弄清楚为什么)新的软件会立即安装并激活而无需等待(即使没有发送任何消息)。 p>

这怎么可能?

我实现了 2 种方法来检查更新并做出相应的反应,这两种方法都会导致相同的问题。

第一种方式,来自官方Docs

public async registerServiceWorker() {
  this.workbox = new Workbox('/sw.js', {});
  try {
    this.workbox.addEventListener('waiting', () => promptTheUser());
    this.swRegistration = await this.workbox.register();
  } catch (e) {
    console.log('[SW] error registering service worker', e);
  }    
}

public async checkForUpdate() {
    return await this.swRegistration.update();
}

public activateNow() { // Called in the user prompt
    this.workbox.addEventListener('controlling', (event) => {
      window.location.reload();
    });
    if (this.swRegistration && this.swRegistration.waiting) {
      messageSW(this.swRegistration.waiting, { type: 'SKIP_WAITING' });
    }
}

第二种方式,使用ServiceWorkerRegistration.onupdatefoundServiceWorkerContainer.oncontrollerchange的方式:

public async registerServiceWorker() {
    this.workbox = new Workbox('/sw.js', {});
    this.swRegistration = await this.workbox.register();
    this.swRegistration.installing.addEventListener('statechange', () => {
      if (this.swRegistration.waiting) {
        promptTheUser();
      }
    });
}

public async checkForUpdate() {
    return await this.swRegistration.update();
}

public activateNow() {
    navigator.serviceWorker.addEventListener('controllerchange', () => {
      window.location.reload();
    });
    if (this.swRegistration && this.swRegistration.waiting) {
      messageSW(this.swRegistration.waiting, { type: 'SKIP_WAITING' });
    }
}

方法 registerServiceWorker() 在应用程序启动时被调用。 两种方式都应该产生相同的结果,但如果没有达到“控制”状态,它们就不起作用。相反,新的软件只是安装一个激活的。

因此,页面永远不会重新加载,并且我的用户提示保持打开状态...

有什么想法吗?

【问题讨论】:

  • 您所描述的内容听起来更像是浏览器错误,而不是 Workbox 或您的软件的问题。我的理解是,每当安装了新的 SW 并且已经有一个活动的 SW 控制了至少一个客户端时,该新的 SW 将一直等待直到调用 skipWaiting(),或者直到所有活动的 SW 的客户端都关闭。如果您可以重现不同的行为,我建议您使用 crbug.com/new 提交 Chrome 错误。

标签: service-worker workbox


【解决方案1】:

好的,我发现了问题。没有触发“controllerchange”事件的原因是在第一次安装服务工作者时,如果页面没有重新加载,则不会声明客户端。我之所以发现这个,是因为我绝望地阅读了Workbox.ts 的源代码并偶然发现了这个:

注意:第一次安装 Service Worker 时,它将处于活动状态 但不要开始控制页面,除非clients.claim() 是 在 service worker 中调用。

对我来说,这是一条非常重要的信息,但在文档(或者可以在网上找到的各种状态图)中没有充分强调。

所以我通过在第一次安装后调用 clients.claim() 解决了我的问题(以便它对用户透明),并且所有后续更新都会触发用户重新加载页面的通知。

希望这可以帮助遇到这个问题的其他人??

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-21
    • 2019-12-08
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 2015-02-19
    • 2015-08-25
    • 2012-07-12
    相关资源
    最近更新 更多