javascript - service worker 不会跳过等待状态

标签 javascript progressive-web-apps service-worker service-worker-events

我还在做实验以掌握服务 worker ,我遇到了一个问题,可能是因为我缺乏 JavaScript 和服务 worker 的专业知识。

当我希望新服务 worker 使用 postMessage()skipWaiting() 时,就会出现问题。如果我显示一个带有按钮的弹出窗口,并在那里绑定(bind)对 postMessage() 的调用,一切正常。如果我直接调用 postMessage(),它不起作用。这是一个竞争条件,因为它SOMETIMES有效,但我无法确定竞争条件。

顺便说一句,postMessage() 调用有效,service worker 正在记录它在收到消息时应该做的事情:

// Listen to messages from clients.
self.addEventListener('message', event => {
    switch(event.data) {
        case 'skipWaiting': self.skipWaiting(); console.log('I skipped waiting... EXTRA');
            break;
    }
}); 

这是代码。重要的是 if (registration.waiting) 条件。未注释的代码有效,注释的代码无效:

// Register service worker.
if ('serviceWorker' in navigator) {
    // Helpers to show and hide the update toast.
    let hideUpdateToast = () => {
        document.getElementById('update_available').style.visibility = 'hidden';
    };

    let showUpdateToast = (serviceworker) => {
        document.getElementById('update_available').style.visibility = 'visible';
        document.getElementById('force_install').onclick = () => {
            serviceworker.postMessage('skipWaiting');
            hideUpdateToast();
        };
        document.getElementById('close').onclick = () => hideUpdateToast();
    };

    window.addEventListener('load', () => {

        let refreshing = false;
        navigator.serviceWorker.addEventListener('controllerchange', () => {
            if (refreshing) return;
            refreshing = true;
            window.location.reload();
        });

        navigator.serviceWorker.register('/sw.js').then(registration => {
            // 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', () => {
                // return;  // FIXME
                registration.installing.onstatechange = function () {  // No arrow function because 'this' is needed.
                    if (this.state == 'installed') {
                        if (!navigator.serviceWorker.controller) {
                            console.log('First install for this service worker.');
                        } else {
                            console.log('New service worker is ready to activate.');
                            showUpdateToast(this);
                        }
                    }
                };
            });

            // 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('New service worker is waiting.');
                // showUpdateToast(registration.waiting);

                // The above works, but this DOESN'T WORK.
                registration.waiting.postMessage('skipWaiting');
            }

        }).catch(error => {
            console.log('Service worker registration failed!');
            console.log(error);
        });
    });
}

为什么使用按钮 onclick 事件的间接调用有效,但调用 postMessage() 却无效?

我完全不知所措,我敢打赌答案很简单,只是我太盲目了,看不到它。

非常感谢。

最佳答案

看起来像是 Chromium 或 WebKit 中的错误,因为此代码在 Firefox 中始终有效,但在 Chrome 和 Edge 中大部分时间都失败了。

我已经向 Chromium 报告了该错误,让我们看看它是错误还是我的代码很奇怪。我已经设法构建了仍然重现问题的尽可能小的代码,它非常小并且可以在错误报告中找到。

报告可见here .

抱歉打扰了,我会继续调查这个问题,但无论我如何尝试,代码仍然时不时地失败,我无法在我的代码中发现竞争条件。

关于javascript - service worker 不会跳过等待状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66031376/

相关文章:

javascript - 生成数字并将其写入剪贴板

sqlite - 离线优先方法和 PWA 的区别?

angular - 无法使用 Angular cli 以 Angular 注册服务 worker

javascript - iPhone 的网页 - 大字体而不是滚动?

javascript - 简单的 JS 适用于除 Safari 之外的所有浏览器

android - Chrome - Android - 刷新 PWA

progressive-web-apps - 不会被预缓存。配置 maximumFileSizeToCacheInBytes 以更改此限制 (PWA)

html - 显示 "This website has been updated in the background"的网络应用程序

javascript - Angular.js ng-repeat 回调

javascript - 如何制作持久化PWA缓存?