Service Worker 有时无需等待即可安装
Service Worker sometimes installs without waiting
我在我的 Angular 应用程序中使用 Workbox,我每 15 分钟检查一次更新,以便在部署新版本时通知用户。
找到更新后,新的 Service Worker 已安装但未激活,因为此时我可以提示用户重新加载页面:
点击确定后,我可以通知我的SW跳过等待,因为他有这个EventListener:
addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
skipWaiting();
}
});
这很好用,但有时(我还没弄明白为什么)新软件会立即安装并激活而无需等待(即使没有收到消息)已发送)。
怎么会这样?
我实现了 2 种方法来检查更新并做出相应的反应,两者都会导致同样的问题。
第一种,来自官方Docs:
public async registerServiceWorker() {
this.workbox = new Workbox('/sw.js', {});
try {
this.workbox.addEventListener('waiting', () => promptTheUser());
this.swRegistration = await this.workbox.register();
} catch (e) {
console.log('[SW] error registering service worker', e);
}
}
public async checkForUpdate() {
return await this.swRegistration.update();
}
public activateNow() { // Called in the user prompt
this.workbox.addEventListener('controlling', (event) => {
window.location.reload();
});
if (this.swRegistration && this.swRegistration.waiting) {
messageSW(this.swRegistration.waiting, { type: 'SKIP_WAITING' });
}
}
第二种方式,使用ServiceWorkerRegistration.onupdatefound and ServiceWorkerContainer.oncontrollerchange的一种:
public async registerServiceWorker() {
this.workbox = new Workbox('/sw.js', {});
this.swRegistration = await this.workbox.register();
this.swRegistration.installing.addEventListener('statechange', () => {
if (this.swRegistration.waiting) {
promptTheUser();
}
});
}
public async checkForUpdate() {
return await this.swRegistration.update();
}
public activateNow() {
navigator.serviceWorker.addEventListener('controllerchange', () => {
window.location.reload();
});
if (this.swRegistration && this.swRegistration.waiting) {
messageSW(this.swRegistration.waiting, { type: 'SKIP_WAITING' });
}
}
在应用程序启动时调用 registerServiceWorker() 方法。
这两种方法应该产生相同的结果,但是如果未达到“控制”状态,它们将不起作用。相反,新的软件只是安装并激活。
结果,页面从未重新加载,我的用户提示保持打开状态...
有什么想法吗?
好的,我找到问题了。 “controllerchange”事件没有被触发的原因是 在第一次安装 service worker 时,如果页面没有重新加载,客户端就不会被认领。我之所以发现这个是因为在绝望中我阅读了 Workbox.ts 的源代码并偶然发现了这个:
Note: the first time a service worker is installed it will active
but not start controlling the page unless clients.claim()
is
called in the service worker.
对我来说,这是一条非常重要的信息,但在文档(或可以在网上找到的各种状态图)中没有足够突出显示。
所以我通过在第一次安装后调用 clients.claim() 解决了我的问题(这样它对用户是透明的),所有后续更新都会触发用户重新加载页面的通知。
希望这可以帮助 运行 遇到此问题的其他人
我在我的 Angular 应用程序中使用 Workbox,我每 15 分钟检查一次更新,以便在部署新版本时通知用户。
找到更新后,新的 Service Worker 已安装但未激活,因为此时我可以提示用户重新加载页面:
点击确定后,我可以通知我的SW跳过等待,因为他有这个EventListener:
addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
skipWaiting();
}
});
这很好用,但有时(我还没弄明白为什么)新软件会立即安装并激活而无需等待(即使没有收到消息)已发送)。
怎么会这样?
我实现了 2 种方法来检查更新并做出相应的反应,两者都会导致同样的问题。
第一种,来自官方Docs:
public async registerServiceWorker() {
this.workbox = new Workbox('/sw.js', {});
try {
this.workbox.addEventListener('waiting', () => promptTheUser());
this.swRegistration = await this.workbox.register();
} catch (e) {
console.log('[SW] error registering service worker', e);
}
}
public async checkForUpdate() {
return await this.swRegistration.update();
}
public activateNow() { // Called in the user prompt
this.workbox.addEventListener('controlling', (event) => {
window.location.reload();
});
if (this.swRegistration && this.swRegistration.waiting) {
messageSW(this.swRegistration.waiting, { type: 'SKIP_WAITING' });
}
}
第二种方式,使用ServiceWorkerRegistration.onupdatefound and ServiceWorkerContainer.oncontrollerchange的一种:
public async registerServiceWorker() {
this.workbox = new Workbox('/sw.js', {});
this.swRegistration = await this.workbox.register();
this.swRegistration.installing.addEventListener('statechange', () => {
if (this.swRegistration.waiting) {
promptTheUser();
}
});
}
public async checkForUpdate() {
return await this.swRegistration.update();
}
public activateNow() {
navigator.serviceWorker.addEventListener('controllerchange', () => {
window.location.reload();
});
if (this.swRegistration && this.swRegistration.waiting) {
messageSW(this.swRegistration.waiting, { type: 'SKIP_WAITING' });
}
}
在应用程序启动时调用 registerServiceWorker() 方法。 这两种方法应该产生相同的结果,但是如果未达到“控制”状态,它们将不起作用。相反,新的软件只是安装并激活。
结果,页面从未重新加载,我的用户提示保持打开状态...
有什么想法吗?
好的,我找到问题了。 “controllerchange”事件没有被触发的原因是 在第一次安装 service worker 时,如果页面没有重新加载,客户端就不会被认领。我之所以发现这个是因为在绝望中我阅读了 Workbox.ts 的源代码并偶然发现了这个:
Note: the first time a service worker is installed it will active but not start controlling the page unless
clients.claim()
is called in the service worker.
对我来说,这是一条非常重要的信息,但在文档(或可以在网上找到的各种状态图)中没有足够突出显示。
所以我通过在第一次安装后调用 clients.claim() 解决了我的问题(这样它对用户是透明的),所有后续更新都会触发用户重新加载页面的通知。
希望这可以帮助 运行 遇到此问题的其他人