我上周一直在为Service Worker工作,目前有一个很棒的安装方法可以离线缓存文件并推送通知。
还有最后一件事,我希望能够在UI中显示服务工作者的某些状态的消息,目前我有以下代码用于激活状态:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.addEventListener('controllerchange',function(event) {
navigator.serviceWorker.controller.addEventListener('statechange', function() {
if (this.state === 'activated') {
document.getElementById('offlineNotification').classList.remove('hidden');
}
});
});
}
现在我想为安装状态创建一条消息,允许我显示类似“脱机服务正在更新”的消息,如果有人正在处理此问题,并知道如何操作,请让我知道。
我已经尝试了相同的代码但是使用“if(this.state ==='安装')”
和
“if(this.state ==='install'”
似乎都没有效果。
答案 0 :(得分:4)
服务工作者的生命周期与您的网页完全分开。 要为您的站点安装服务工作者,您需要注册它。
self.addEventListener('install', function(event) {
// Perform install steps
});
当我们安装时,激活步骤将随之而来,这是处理旧缓存管理的绝佳机会。
self.addEventListener('activate', function(event) {
// Perform activate steps, Typically cache management.
});
在激活步骤之后,服务工作者将控制属于其范围的所有页面,尽管第一次注册服务工作者的页面在再次加载之前将不会被控制。
一旦服务人员处于控制状态,它将处于以下两种状态之一:either the service worker will be terminated
以节省内存,或it will handle fetch and message events
在您的页面发出网络请求或消息时发生。
你也可以试试像,
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(function(reg) {
// updatefound is fired if service-worker.js changes.
reg.onupdatefound = function() {
var installingWorker = reg.installing;
installingWorker.onstatechange = function() {
switch (installingWorker.state) {
case 'installed':
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is available; please refresh."
console.log('New or updated content is available.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a "Content is cached for offline use." message.
console.log('Content is now available offline!');
}
break;
case 'redundant':
console.error('The installing service worker became redundant.');
break;
}
};
};
}).catch(function(e) {
console.error('Error during service worker registration:', e);
});
}
答案 1 :(得分:0)
查看ServiceWorker Cookbook上的live flowchart demo和Telegram使用的code snippet,以便在有更新时通知用户。
答案 2 :(得分:0)
这是因为代码中的this
始终引用页面的activated
服务工作者。
navigator.serviceWorker.controller
只会引用您页面的一名服务工作者,而后者是当前控制中的服务工作者。如果在服务页面控制着您的页面的同时安装了另一个服务页面,那么它将在您的ServiceWorkerRegistration
(即installing
或{{ 1}})。
您想要的是在waiting
事件处理程序(而不是ServiceWorkerRegistration
)内引用此navigator.serviceWorker.controller
上的各种状态(而不是您的updatefound
):< / p>
controllerchange
我相信if ('serviceWorker' in navigator) {
const registration = await navigator.serviceWorker.register('serviceWorker.js');
// Or, if not using async/await...
//navigator.serviceWorker.register('serviceWorker.js').then(function(registration) {
registration.addEventListener('updatefound', function(e) {
const newSw = e.target.installing || e.target.waiting;
newSw.addEventListener('statechange', function() {
if (this.state === 'activated') {
document.getElementById('offlineNotification').classList.remove('hidden');
/* else if handlers for any of the following (or, better yet, a switch statement):
'installing'
'installed'
'activating'
'activated' (handled above)
'redundant'
*/
}
});
});
}
仅在控制器合法更改时才调用,只有当您通过controllerchange
和skipWaiting()
在服务工作者中明确声明对客户端的控制权时才会发生或者,如果您在开发工具中摆弄,并强迫新的服务人员进行控制。这样,您将永远不会在该控制器上看到clients.claim()
,因为它已经超过了installing
,installing
和installed
才能触发activating
事件。
一些有用的链接:
MDN - ServiceWorkerContainer.controller
MDN - ServiceWorkerRegistration
MDN - ServiceWorker.onstatechange
A detailed demonstration of service worker lifecycle and state change detection