即使加载新版本的服务后,服务人员仍可能显示旧版本的应用程序?

dum*_*ter 5 javascript service-worker workbox

抱歉,我没有这个问题的可重复测试案例,因为我什至从未亲眼看到过。我只知道发生这种情况是因为我的应用程序中有客户端登录以及用户的抱怨。

问题是:

  1. 我部署了新版本的应用
  2. 用户访问我的网站,获取新版本并成功运行
  3. 用户再次访问我的网站并获得了我的应用的旧版本

我正在使用服务人员,我希望可以为这种情况不会发生提供一些保证。当新版本包括IndexedDB模式迁移时,这尤其令人不安,因为那时我的应用程序的旧版本甚至无法正常工作。

更多细节:

我正在使用Workbox 4.3.1。我的服务人员基本上是:

importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
workbox.precaching.precacheAndRoute([]);
workbox.routing.registerNavigationRoute("/index.html", {
    blacklist: [
        new RegExp("^/static"),
        new RegExp("^/sw.js"),
    ],
});
Run Code Online (Sandbox Code Playgroud)

workbox.precaching.precacheAndRoute([]);被填充workboxBuild.injectManifest。我可以手动确认是否填写了正确的文件。通常,服务人员可以正常工作。我可以在浏览器开发工具中看到它。我可以断开与Internet的连接,但仍可以使用我的应用程序。一切似乎都很好。就像我在上面说的那样,我从未见过这个问题发生,并且我没有可复制的测试用例。

但是我的一些用户遇到了上述问题。我尝试使用客户端错误日志记录进行调查。我向我的应用程序添加了一些代码,以将其版本号存储在localStorage中,并在初始加载时将其与当前运行的版本号进行比较。如果localStorage中的版本比当前正在运行的版本新(即,它过去成功运行了一个新版本,但现在又回到了较旧的版本),它将记录版本号以及一些其他信息:

let registrations = [];
if (window.navigator.serviceWorker) {
    registrations = await window.navigator.serviceWorker.getRegistrations();
}
log({
    hasNavigatorServiceWorker:
        window.navigator.serviceWorker !== undefined,
    registrationsLength: registrations.length,
    registrations: registrations.map(r => {
        return {
            scope: r.scope,
            active: r.active
                ? {
                      scriptURL: r.active.scriptURL,
                      state: r.active.state,
                  }
                : null,
            installing: r.installing
                ? {
                      scriptURL: r.installing.scriptURL,
                      state: r.installing.state,
                  }
                : null,
            waiting: r.waiting
                ? {
                      scriptURL: r.waiting.scriptURL,
                      state: r.waiting.state,
                  }
                : null,
        };
    }),
})
Run Code Online (Sandbox Code Playgroud)

在我的日志中,我发现只有1%的用户会出现此问题。这些用户丰富了Firefox(占总流量的4%,但针对此问题的日志条目占18%),但是Firefox在所有浏览器和操作系统中均会发生。

而且我看到几乎所有记录都具有以下值:

{
    hasNavigatorServiceWorker: true,
    registrationsLength: 1,
    registrations: [{
        "scope": "https://example.com/",
        "active": {
            "scriptURL": "https://example.com/sw.js",
            "state": "activated"
        },
        "installing": null,
        "waiting": null
    }]
}
Run Code Online (Sandbox Code Playgroud)

据我所知,这些都是正确的值。

我还应该注意,我的JavaScript文件的URL中有一个哈希,因此,不可能是我的服务器在用户请求新版本时以某种方式返回我的JavaScript的旧版本。

那么,可能会发生什么?如何解释这种观察到的行为?我还能记录什么以进一步调试?

我想出的唯一方案对我来说似乎非常不现实。喜欢...

  1. 用户加载v1,服务工作者由于某种原因失败
  2. 用户加载v2,服务工作者由于某种原因失败
  3. 由于所有先前的服务工作者均失败,因此用户以某种方式从其浏览器缓存中获取v1,但现在该服务工作者可以正常工作并将其存储为当前版本

但是我没有证据表明服务人员曾经失败过。我的错误日志中没有任何内容。没有用户抱怨离线支持中断。

如果有帮助,发生此情况的实际网站是https://play.basketball-gm.com/,服务人员在https://play.basketball-gm.com/sw.js,所有代码均为在GitHub上可用

自从大约一年前我开始使用服务人员以来,这个问题一直存在。我终于开始写一个Stack Overflow的问题,因为我已经放弃了希望自己能够解决这个问题,甚至创建一个可重现的测试用例。