【问题标题】:What is the purpose of SwUpdate.activateUpdate() in Angular?Angular 中 SwUpdate.activateUpdate() 的目的是什么?
【发布时间】:2019-04-03 11:34:19
【问题描述】:

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

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

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

activateUpdate() 调用的目的是什么?为什么在 reload 足够的时候调用它?

【问题讨论】:

  • 你找到答案了吗?

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


【解决方案1】:

关于 Angular ServiceWorker 在后台所做的一些背景:

  • 软件始终只有一个版本,但它可以有多个应用版本。
  • 它将client IDs 映射到应用程序版本,因此它知道要为每个客户端提供哪个版本。
  • 找到新版本时,会下载并标记为最新版本。
  • 从那时起,新客户端(例如新选项卡)将使用最新版本,但现有客户端(选项卡)仍将获得其先前分配的版本。

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


现在,回到activeUpdate()

这基本上告诉软件将最新版本分配给客户端。操作完成后,来自客户端的新请求将使用最新的应用程序版本提供服务。这是不安全的,因此建议重新加载页面以确保所有代码都来自新版本。


只需重新加载就足够了吗?

这基本上取决于浏览器如何在重新加载时分配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/ btw 中所做的事情。)

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


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

【讨论】:

  • 感谢您提供的信息丰富的回答。您能解释一下如何编写在下一个应用内导航中重新加载页面的第三个选项吗?
  • 还有关于第一个(立即更新)。这是否意味着应用程序/模块/服务的一部分将具有新代码,如果是,哪些部分?直接说:页面已打开并且更新已准备好似乎是一个不错的选择,所以既然用户刚刚到达,让我们激活新版本(如果它在代码方面是安全的)。
  • 我不明白第二个问题:D
  • 感谢@gkalpak 的精彩回答。学到了很多,也回答了很多问题。
【解决方案2】:

从 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);
}

【讨论】:

  • 这仍然没有说明原因,与简单地重新加载页面有什么区别?
猜你喜欢
  • 2018-02-25
  • 2016-01-17
  • 1970-01-01
  • 2022-01-01
  • 2018-09-12
  • 1970-01-01
  • 2018-05-03
  • 2018-03-10
  • 2017-12-08
相关资源
最近更新 更多