Angular中SwUpdate.activateUpdate()的用途是什么?

时间:2019-04-03 11:34:19

标签: angular service-worker progressive-web-apps

Angular documentation提供了以下示例来激活软件更新:

constructor(updates: SwUpdate) {
  updates.available.subscribe(event => {
    if (promptUser(event)) {
        updates.activateUpdate().then(() => document.location.reload());
    }
  });
}

根据我的观察,调用本身不足以激活新版本,需要重新加载。但是,即使没有document.location.reload()调用,activateUpdate()也足够。

activateUpdate()呼叫的目的是什么?重新加载就足够了,为什么还要调用它呢?

2 个答案:

答案 0 :(得分:2)

Angular ServiceWorker的幕后工作背景:

  • SW总是有一个版本,但可以有多个版本的应用程序。
  • 它保持[客户端ID]到应用程序版本的映射,因此它知道为每个客户端提供哪个版本。
  • 找到新版本后,它将下载并标记为最新版本。
  • 从那时起,将为新客户(例如新标签页)提供该最新版本,但是现有客户(标签页)仍将获得旧版本。

此行为与ServiceWorkers通常的工作方式略有不同。它旨在允许向新客户端提供最新版本,但又不破坏现有客户端(通过向他们提供新内容,而这些新内容并非旨在与他们已经在使用的旧HTML / CSS / JS代码一起使用)。


现在,回到activeUpdate()

这基本上告诉SW将客户端设置为最新版本。操作完成后,来自客户端的新请求将得到最新的应用程序版本。这是不安全的,因此建议重新加载页面以确保所有代码都来自新版本。


重新加载就足够了吗?

这基本上取决于浏览器如何在重新加载时分配Client.id。如果浏览器在重新加载时为标签分配了新的ID,则SW仍将提供最新版本,因此swUpdate.activeUpdate()是不必要的。另一方面,如果浏览器保留相同的客户端ID,则SW将提供不带swUpdate.activeUpdate()的旧版本。

当前,Chrome似乎分配了一个新ID(因此,activeUpdate()在重新加载之前是不必要的)。我在the SW spec中找不到结论性的内容,因此我不确定这是否符合规范以及所有浏览器是否都执行相同操作。 (过去,浏览器过去的行为可能也不同,因此activeUpdate()是必需的,但是此后规范/浏览器已进行了更新,如果您打算重新加载,则会变得多余。)


因此,如果您确认支持的浏览器在这方面的行为符合预期,则无需在重新加载之前调用activeUpdate()

请注意,文档示例只是可用API的简化图示。在真实的应用程序中,有几种处理更新的方法(取决于应用程序的要求)。

例如,您可以:

  1. 立即激活更新(如果您确定您的应用程序可以处理此更新),而不重新加载。
  2. 显示有关更新可用的通知,并让用户单击以重新加载(并由此更新)。
  3. 让应用知道更新可用,并在下一次应用内导航时自动重新加载。 (这就是我们在https://angular.io中所做的事情。)

同样,并非所有策略都适用于所有类型的应用,因此请选择最适合您的一种。


编辑:
顺便说一句,如果您对如何改进文档有任何建议,请提出一个问题(或者最好还是提出提起请求)!

答案 1 :(得分:0)

从github代码中,我了解的是,activateUpdate()将对服务工作者线程执行postMessage(),以使其了解新数据和状态,并在解决诺言之后(服务工作者)线程知道这一点),然后重新加载页面。

https://github.com/angular/angular/blob/7.2.11/packages/service-worker/src/update.ts#L57-L64

activateUpdate(): Promise<void> {
    if (!this.sw.isEnabled) {
      return Promise.reject(new Error(ERR_SW_NOT_SUPPORTED));
    }
    const statusNonce = this.sw.generateNonce();
    return this.sw.postMessageWithStatus('ACTIVATE_UPDATE', {statusNonce}, statusNonce);
}

https://github.com/angular/angular/blob/master/packages/service-worker/src/low_level.ts#LC105

postMessageWithStatus(type: string, payload: Object, nonce: number): Promise<void> {
    const waitForStatus = this.waitForStatus(nonce);
    const postMessage = this.postMessage(type, payload);
    return Promise.all([waitForStatus, postMessage]).then(() => undefined);
}