抱歉,我没有这个问题的可重现测试用例,因为我自己从未见过它发生过。我只知道这是因为客户端登录我的应用程序和用户的投诉。
问题是:
- 我部署了新版本的应用
- 用户访问我的站点,获取新版本并成功运行
- 用户再次访问我的网站并获得我的应用程序的旧版本
我正在使用 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。
那么,可能发生了什么?如何解释这种观察到的行为?我还可以记录什么以进一步调试它?
我能想出的唯一场景对我来说似乎非常难以置信。喜欢...
- 用户加载 v1,service worker 因某种原因失败
- 用户加载 v2,service worker 因某种原因失败
- 用户以某种方式从他们的浏览器缓存中获取 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/