admin管理员组文章数量:1313089
What I am trying to achieve:
render page with loader/spinner
if
service-worker.js
is registered and active, then check for updates- if no updates, then remove loader
- if
updatefound
and new version installed, then reload the page
- else register
service-worker.js
- when
updatefound
, meaning new one was installed, remove loader
- when
I am using sw-precache
module for me to generate service-worker.js
and following registration code:
window.addEventListener('load', function() {
// show loader
addLoader();
navigator.serviceWorker.register('service-worker.js')
.then(function(swRegistration) {
// react to changes in `service-worker.js`
swRegistration.onupdatefound = function() {
var installingWorker = swRegistration.installing;
installingWorker.onstatechange = function() {
if(installingWorker.state === 'installed' && navigator.serviceWorker.controller){
// updated content installed
window.location.reload();
} else if (installingWorker.state === 'installed'){
// new sw registered and content cached
removeLoader();
}
};
}
if(swRegistration.active){
// here I know that `service-worker.js` was already installed
// but not sure it there are changes
// If there are no changes it is the last thing I can check
// AFAIK no events are fired afterwards
}
})
.catch(function(e) {
console.error('Error during service worker registration:', e);
});
});
After reading the spec it is clear that there are no handlers for something like updatenotfound
. Looks like serviceWorker.register
checks if service-worker.js
changed internally by running get-newest-worker-algorithm, but I cannot see similar methods exposed via public api.
I think my options are:
- wait for couple of seconds after service worker registration bees active to see if
onupdatefound
is fired fire custom events fromservice-worker.js
code if cache was not updated
Any other suggestions?
Edit:
I've came up with some code which solves this issue by using postMessage()
between SW registration and SW client (as @pate suggested)
Following demo tries to achieve checks through postMessage
between SW client and SW registration, but fails as SW code is already cached DEMO
Edit:
So by now it looks like I cannot implement what I want because:
- when service worker is active you cannot check for updates by evaluating some code in SW - this is still the same cached SW, no changes there
- you need to wait for
onupdatefound
, there is nothing else that will notify of changes in SW activation
of older SW es beforeonupdatefound
- if there is no change, nothing fires after
activation
- SW registration
update()
is immature, keeps changing,Starting with Chrome 46, update() returns a promise that resolves with 'undefined' if the operation pleted successfully or there was no update
- setting timeout to postpone view rendering is suboptimal as there is no clear answer to how long should it be set to, it depends on SW size as well
What I am trying to achieve:
render page with loader/spinner
if
service-worker.js
is registered and active, then check for updates- if no updates, then remove loader
- if
updatefound
and new version installed, then reload the page
- else register
service-worker.js
- when
updatefound
, meaning new one was installed, remove loader
- when
I am using sw-precache
module for me to generate service-worker.js
and following registration code:
window.addEventListener('load', function() {
// show loader
addLoader();
navigator.serviceWorker.register('service-worker.js')
.then(function(swRegistration) {
// react to changes in `service-worker.js`
swRegistration.onupdatefound = function() {
var installingWorker = swRegistration.installing;
installingWorker.onstatechange = function() {
if(installingWorker.state === 'installed' && navigator.serviceWorker.controller){
// updated content installed
window.location.reload();
} else if (installingWorker.state === 'installed'){
// new sw registered and content cached
removeLoader();
}
};
}
if(swRegistration.active){
// here I know that `service-worker.js` was already installed
// but not sure it there are changes
// If there are no changes it is the last thing I can check
// AFAIK no events are fired afterwards
}
})
.catch(function(e) {
console.error('Error during service worker registration:', e);
});
});
After reading the spec it is clear that there are no handlers for something like updatenotfound
. Looks like serviceWorker.register
checks if service-worker.js
changed internally by running get-newest-worker-algorithm, but I cannot see similar methods exposed via public api.
I think my options are:
- wait for couple of seconds after service worker registration bees active to see if
onupdatefound
is fired fire custom events fromservice-worker.js
code if cache was not updated
Any other suggestions?
Edit:
I've came up with some code which solves this issue by using postMessage()
between SW registration and SW client (as @pate suggested)
Following demo tries to achieve checks through postMessage
between SW client and SW registration, but fails as SW code is already cached DEMO
Edit:
So by now it looks like I cannot implement what I want because:
- when service worker is active you cannot check for updates by evaluating some code in SW - this is still the same cached SW, no changes there
- you need to wait for
onupdatefound
, there is nothing else that will notify of changes in SW activation
of older SW es beforeonupdatefound
- if there is no change, nothing fires after
activation
- SW registration
update()
is immature, keeps changing,Starting with Chrome 46, update() returns a promise that resolves with 'undefined' if the operation pleted successfully or there was no update
- setting timeout to postpone view rendering is suboptimal as there is no clear answer to how long should it be set to, it depends on SW size as well
- 1 Hi, do you have any update on this ? – Samuel Maisonneuve Commented Jun 21, 2018 at 11:03
- Actually I do not, apps in production do this crazy refresh after initial load has happened (view rendered) and changes were detected subsequently – Ivar Commented Jun 21, 2018 at 12:58
- Ok thanks for your answer – Samuel Maisonneuve Commented Jun 22, 2018 at 13:50
- unbelievable, tried an entire day .. have the exact same usecase.did you end up implementing a timer? I'm thinking about it, most apps have some loader screens for a couple seconds anyways. Could also be disabled by using session storage I guess. Still seems unreliable to me – maxischl Commented May 7, 2023 at 18:49
- @maxischl this was "some time" ago. I'm not entirely sure if the API is still the same or if it changed for the better. – Ivar Commented May 8, 2023 at 13:56
2 Answers
Reset to default 4The other answer, provided by Fabio, doesn't work. The Service Worker script has no access to the DOM. It's not possible to remove anything from the DOM or, for instance, manipulate any data that is handling DOM elements from inside the Service Worker. That script runs separately with no shared state.
What you can do, though, is send messages between the actual page-running JS and the Service Worker. I'm not sure if this is the best possible way to do what the OP is asking but can be used to achieve it.
- Register an onmessage handler on the page
- Send a message from the SW's activate or install event to the page
- Act accordingly when the message is received on the page
I have myself kept SW version number in a variable inside the SW. My SW has then posted that version number to the page and the page has stored it into the localStorage of the browser. The next time the page is loaded SW posts it current version number to the page and the onmessage handler pares it to the currently stored version number. If they are not the same, then the SW has been updated to some version number that was included in the mssage. After that I've updated the localStorage copy of the version number and done this and that.
This flow could also be done in the other way around: send a message from the page to the SW and let SW answer something back, then act accordingly.
I hope I was able to explain my thoughts clearly :)
The only way that pops up in my mind is to start the loader normally and then remove it in the service-worker, in the install function. I will give this a try, in your service-worker.js:
self.addEventListener('install', function(e) {
console.log('[ServiceWorker] Install');
e.waitUntil(
caches.open(cacheName).then(function(cache) {
console.log('[ServiceWorker] Caching app shell');
return cache.addAll(filesToCache);
}).then(function() {
***removeLoader();***
return self.skipWaiting();
})
);
});
本文标签: javascriptHow ServiceWorker check if ready to updateStack Overflow
版权声明:本文标题:javascript - How: ServiceWorker check if ready to update - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741932261a2405643.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论