javascript - 即使在加载新版本后,Service Worker 仍可能显示旧版本应用程序的情况?

标签 javascript service-worker workbox

抱歉,我没有这个问题的可重现测试用例,因为我自己从未见过它发生过。我只知道这是因为客户端登录我的应用程序和用户的投诉。

问题是:

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

我正在使用 Service Worker,我希望它可以为这种情况不会发生提供一些保证。当新版本包含 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"),
    ],
});

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

查看我的日志,我发现只有大约 1% 的用户会出现此问题。 Firefox 在这些用户中变得丰富(占总流量的 4%,但占此问题日志条目的 18%),但它发生在所有浏览器和操作系统中。

我看到几乎所有记录都有这些值:

{
    hasNavigatorServiceWorker: true,
    registrationsLength: 1,
    registrations: [{
        "scope": "https://example.com/",
        "active": {
            "scriptURL": "https://example.com/sw.js",
            "state": "activated"
        },
        "installing": null,
        "waiting": null
    }]
}

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

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

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

我能想出的唯一场景对我来说似乎非常难以置信。喜欢...

  1. 用户加载 v1,service worker 因某种原因失败
  2. 用户加载 v2,service worker 因某种原因失败
  3. 用户以某种方式从他们的浏览器缓存中获取 v1,因为之前所有的 service worker 都失败了,但现在 service worker 可以正常工作并将其存储为当前版本

但我没有证据表明 service worker 曾经失败过。我的错误日志中没有任何内容。没有用户提示离线支持中断。

如果有帮助,发生这种情况的实际网站是 https://play.basketball-gm.com/ , service worker 在 https://play.basketball-gm.com/sw.js ,所有代码都是available on GitHub .

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

最佳答案

用户以某种方式从他们的缓存中获取旧版本。删除过时的缓存应该可以解决问题。一旦安装了新的 service worker 并且没有使用以前的版本,新的就会激活,并且您会收到一个 activate 事件。因为旧版本不在了,现在是删除未使用的缓存的好时机。

self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.filter(function(cacheName) {
          // Return true if you want to remove this cache,
          // but remember that caches are shared across
          // the whole origin
        }).map(function(cacheName) {
          return caches.delete(cacheName);
        })
      );
    })
  );
});

在激活期间,其他事件(如 fetch)被放入队列中,因此长时间激活可能会阻止页面加载。尽可能精简您的激活,仅将其用于您在旧版本处于事件状态时不能做的事情。

关于javascript - 即使在加载新版本后,Service Worker 仍可能显示旧版本应用程序的情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58032817/

相关文章:

javascript - 显示错误的动态生成表

javascript - 如何编写一个需要 X 秒的函数?

javascript - 如何仅在 PWA 中而不在网站中显示更新弹出窗口?

localization - 本地化 PWA Web list

javascript - 使用 PhoneGap 和 JQuery Mobile 转到下一页

javascript - Js ReGex 非捕获组不起作用

javascript - Service Worker 加载资源失败:net::ERR_INTERNET_DISCONNECTED

service-worker - 手动重放由 workbox-background-sync 排队的请求

javascript - 如何对 workboxSW 预缓​​存项使用 staleWhileRevalidate?