首页 > 解决方案 > 与 workbox-window.update() 的行为不一致

问题描述

平台

"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"

工作箱版本

5.0.0-rc.0

我正在使用 workbox-windowupdate()方法来触发 service worker 更新检查,如workbox issue #2130中所述。这个问题似乎也与工作箱问题 #2301中的观察有关。

<script type="module">
import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/5.0.0-rc.0/workbox-window.prod.mjs';

if ('serviceWorker' in navigator) {
    const wb = new Workbox('/sw.js');
    // Grab the update button from the UI using jQuery and add a listener to it.
    $('#update-button').on('click', function () {
        wb.update();
    });
    ....
}

</script>

如果找到更新,则加载新的 service worker 并进入等待状态。我监听这个事件(waitingexternalwaiting,在两种情况下都做同样的事情),并询问用户是现在还是以后安装更新。

function handleWaiting(wb) {
    if (confirm("An update is available for this app. Install now?")) {
        wb.messageSW({type: 'SKIP_WAITING'});
    }
}
wb.addEventListener('waiting', event => {
    handleWaiting(wb);
});
wb.addEventListener('externalwaiting', event => {
    handleWaiting(wb);
});

大多数情况下,waiting事件被触发,如果用户接受更新,则服务工作者被激活,我们可以重新加载页面以完成更新过程:

function handleActivated(wb, event) {
    if (event.isUpdate) {
        window.location.reload();
    } else {
        wb.messageSW({ type: 'CLIENTS_CLAIM' });
    }
}
wb.addEventListener('activated', event => {
    handleActivated(wb, event);
});
wb.addEventListener('externalactivated', event => {
    handleActivated(wb, event);
});

如果waiting事件被触发,这个过程可以正常工作。

  1. 对导致 service worker 文件更改的应用程序进行小幅更新。
  2. 按“检查更新”按钮。
  3. 找到新的服务人员并提示用户安装更新
  4. 页面已重新加载。

但是如果externalwaiting事件被触发,那么这段代码就不起作用。新的 service worker 仍处于等待状态,我可以在 Chrome 开发工具中看到。

等待

跳过旧服务人员收到的等待消息

如果用户确认他们想要更新SKIP_WAITING消息,那么旧的、激活的服务工作者定义会接收到该消息。

这是我的日志的摘录,可以证明这一点。

01 [Application 0.0.1.2019.11.05-48] Checking for updates...
02 [Service Worker 2019-11-05 @ 15:23:14] <<<<<<<<<<<<<<< STARTING >>>>>>>>>>>>>>>
03 [Service Worker 2019-11-05 @ 15:23:14] Yay! Workbox 5.0.0-rc.0 is loaded 
04 [Service Worker 2019-11-05 @ 15:23:14] Lifecycle event: [install]
05 [Application 0.0.1.2019.11.05-48] Service Worker lifecycle event: 06 [externalinstalled]
07 [Application 0.0.1.2019.11.05-48] Service Worker lifecycle event: [externalwaiting]
08 [Application 0.0.1.2019.11.05-48] handle waiting...
09 [Service Worker 2019-11-05 @ 15:20:03] Message event: [SKIP_WAITING]

在线的

  1. 用户刚刚按下了“检查更新”按钮。
  2. 一个新的 service worker 版本被发现2019-11-05 @ 15:23:14并且正在被解析。我们称之为 SWv2。
  3. Workbox 由 SWv2 加载。
  4. SWv2install事件处理程序被执行。
  5. 执行 Workbox 窗口externalinstalled事件处理程序。
  6. 执行 Workbox 窗口externalwaiting事件处理程序。
  7. 工作框窗口externalwaiting事件处理程序SKIP_WAITING使用workboxWindow.messageSW()
  8. Service Worker v1 (loaded on 2019-11-05 @ 15:20:03) 接收到跳过等待消息。什么都没发生。SWv2 保持等待状态。

与普通等待事件对比

在以下日志中,您可以看到SKIP_WAITING等待的 service worker 收到了消息: v 2019-11-05 @ 16:07:32。因此更新过程成功完成。

[Application 0.0.1.2019.11.05-52] Checking for updates...
[Service Worker 2019-11-05 @ 16:07:32] <<<<<<<<<<<<<<< STARTING >>>>>>>>>>>>>>>
[Service Worker 2019-11-05 @ 16:07:32] Yay! Workbox 5.0.0-rc.0 is loaded 
[Service Worker 2019-11-05 @ 16:07:32] Lifecycle event: [install]
[Application 0.0.1.2019.11.05-52] Service Worker lifecycle event: [installed]
[Application 0.0.1.2019.11.05-52] Service Worker lifecycle event: [waiting]
[Application 0.0.1.2019.11.05-52] handle waiting...
[Service Worker 2019-11-05 @ 16:07:32] Message event: [SKIP_WAITING]
[Application 0.0.1.2019.11.05-52] Service Worker lifecycle event: [redundant]
[Application 0.0.1.2019.11.05-52] Service Worker lifecycle event: [activating]
[Application 0.0.1.2019.11.05-52] Service Worker lifecycle event: [controlling]
[Service Worker 2019-11-05 @ 16:07:32] Lifecycle event: [activate]
[Application 0.0.1.2019.11.05-52] Service Worker lifecycle event: [activated]
[Application 0.0.1.2019.11.05-52] Reloading this window...
[Application 0.0.1.2019.11.05-53] <<<<<<<<<<<<<<< STARTING >>>>>>>>>>>>>>>
[Application 0.0.1.2019.11.05-53] Preloading 125 images...
[Application 0.0.1.2019.11.05-53] ServiceWorker registered!

有时它只是挂起......

有时,当有新的 Service Worker 版本可用时,事情就会陷入困境。waitingor事件处理程序永远不会被externalwaiting触发。

Chrome 开发工具

发生这种情况时,控制台中没有错误,新版本的 service worker 也没有错误。

解除绑定的唯一方法是停止活动的服务工作者,取消注册并重新加载。

为什么这很重要?

在我敢发布这个应用程序之前,我需要确保更新过程在所有平台上都能完美运行......

如果用户在我发布更新时遇到这些问题中的任何一个,他们将难以获得它,而我对此无能为力。乘以安装数量 == 非常头疼。

这一切都归结为三个问题: 按重要性排列:

  1. 如何处理externalwaiting以便加载和激活新版本的 service worker?如何确保SKIP_WAITING等待的服务人员收到消息?
  2. 为什么生命周期事件在普通品种和外部品种之间有所不同?
    • 出于测试目的,我每次都对服务人员进行相同的更新(预缓存文件的新版本)。
    • 我只在一个选项卡中加载了应用程序。
    • 从普通事件到外部事件的转变似乎是随机的。
  3. 为什么该过程有时会在生命周期的等待阶段之前卡住,我该怎么办?

标签: google-chrome-devtoolsprogressive-web-appsworkboxworkbox-window

解决方案


请注意,这已在 Workbox 窗口中解决。有一个更新的高级配方:

https://developers.google.com/web/tools/workbox/guides/advanced-recipes#offer_a_page_reload_for_users

另请注意,本秘籍中的代码存在(或曾经存在)问题。有关固定代码,请参阅以下问题。

https://github.com/GoogleChrome/workbox/issues/2430


推荐阅读