即使在页面重新加载后也显示服务工作者更新通知

Show service worker update notification even after page reload

我正在使用这个众所周知的模式在服务工作者更新准备好安装时显示通知(此代码进入网页,当然不是服务工作者代码):

// Register service worker.
let newWorker;
if ('serviceWorker' in navigator) {
    function showUpdateNotification () {
        document.getElementById('updatenotification').style['visibility'] = 'visible';
    };

    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js').then(registration => {
            console.log('Service worker registered at scope "' + registration.scope + '".');

            // The commented code below is needed to show the notification after a page reload.
            //
            // if (registration.waiting) {
            //     console.log('Service working in skipwaiting state.');
            //     showUpdateNotification();
            // }
            registration.onupdatefound = () => {
                console.log('Service worker update found.');
                console.log('Installing service worker is', registration.installing);
                newWorker = registration.installing;

                newWorker.onstatechange = function () {
                    console.log('Service worker state changed to', newWorker.state);
                    if (newWorker.state == 'installed' && navigator.serviceWorker.controller) {
                        console.log('New service worker is ready to install on refresh.');
                        showUpdateNotification();
                    }
                };
            };
            console.log('Updating service worker.');
            registration.update();
        }).catch(error => console.log('Service worker not registered (' + error +').'))
    })
}

当然,如果新版本的 Service Worker 已准备好安装,该代码会在网页上显示通知。

问题是,如果此时重新加载页面,则不再显示通知,因为如果安装了新的 service worker 并等待激活,则不再触发 updatefound 事件。

因此,通知只出现 ONCE,当新的 service worker 安装并等待被激活并开始控制页面时,但是一旦页面重新加载,通知是走了。

我已经使用注释代码解决了这个问题:

// The commented code below is needed to show the notification after a page reload.
//
// if (registration.waiting) {
//     console.log('Service working in skipwaiting state.');
//     showUpdateNotification();
// }

此代码在注册时检查是否有某个服务工作者处于等待状态并再次显示通知。

我的问题是:这是正确的吗?我可以安全地使用那个“技巧”还是我在找麻烦?

我是 service workers 的新手,所以我不确定我是否可以做这种事情。

非常感谢。

好吧,很抱歉自己的回复,但或多或​​少我得到了我需要的,同时处理了所有的案例(至少,所有的案例I 需要我的项目)。

我认为下面的代码或多或少涵盖了 service worker 整个生命周期的处理,可以用作一个不太复杂的样板代码。

我使用来自无数来源的信息设计此代码,包括 Whosebug、博客、来自其他 PWA 的代码等。不幸的是,我没有写下每一个信息来源,所以我很抱歉那我想澄清一下,我写了下面的代码,但我没有发明它,我使用了其他人的信息和智慧。

非常感谢!

if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {

        let refreshing = false;
        navigator.serviceWorker.addEventListener('controllerchange', () => {
            console.log('New service worker in charge.');
            if (refreshing) return;
            refreshing = true;
            window.location.reload();
        });

        navigator.serviceWorker.register('/sw.js').then(registration => {
            console.log('Service worker registered.');

            // No controller for this page, nothing to do for now.
            if (!navigator.serviceWorker.controller) {
                console.log('No service worker controlling this page.');
            }    

            // A new service worker has been fetched, watch for state changes.
            //
            // This event is fired EVERY TIME a service worker is fetched and
            // succesfully parsed and goes into 'installing' state. This
            // happens, too, the very first time the page is visited, the very
            // first time a service worker is fetched for this page, when the
            // page doesn't have a controller, but in that case there's no new
            // version available and the notification must not appear.
            //
            // So, if the page doesn't have a controller, no notification shown.
            registration.addEventListener('updatefound', function () {
                console.log('New service worker in installing state.');

                registration.installing.onstatechange = function () {
                    console.log('Service worker state changed to', registration.state);
                    if (registration.state == 'installed') {
                        if (!navigator.serviceWorker.controller) {
                            console.log('First install for this service worker.');
                        } else {
                            console.log('New service worker is ready to install on refresh.');
                        }
                    }
                };
            });

            // If a service worker is in 'waiting' state, then maybe the user
            // dismissed the notification when the service worker was in the
            // 'installing' state or maybe the 'updatefound' event was fired
            // before it could be listened, or something like that. Anyway, in
            // that case the notification has to be shown again.
            //
            if (registration.waiting) {
                console.log('Service working in skipwaiting state.');
            }

            // Well, really this should go into a setInterval() call, but I'm
            // including it here to be exhaustive.
            console.log('Updating service worker.');
            registration.update();
        }).catch(error => console.log('Service worker not registered (' + error +').'))
    })
} else {
    console.log('Service workers not supported.');
}