未捕获(承诺中)DOMException:订阅失败 - 没有活动的 Service Worker

问题描述 投票:0回答:3

我正在尝试订阅用户,但这是我第一次收到错误。 第二次,它可以工作,因为用户已经处于活动状态

这是我的代码:

 if ('serviceWorker' in navigator) {
   console.log('Service Worker is supported');
   navigator.serviceWorker.register('sw.js').then(function(reg) {
     console.log(':^)', reg);
     reg.pushManager.subscribe({
       userVisibleOnly: true
     }).then(function(sub) {
       console.log('endpoint:', sub.endpoint);
       var div = document.getElementById('id');
       div.innerHTML = div.innerHTML + sub.endpoint;
       // var b = document.getElementsByTagName('body')[0];
       //b.appendChild(div);
       //alert(sub.endpoint);
     });
   });
 }

我已经尝试过以下方法,但是

ready.then()
方法没有发生:

 if ('serviceWorker' in navigator) {
   console.log('Service Worker is supported');
   navigator.serviceWorker.register('sw.js').then(function(sreg) {
     console.log(':^)', sreg);
     navigator.serviceWorker.ready.then(function(reg) {
       reg.pushManager.subscribe({
         userVisibleOnly: true
       }).then(function(sub) {
         console.log('endpoint:', sub.endpoint);
         var div = document.getElementById('id');
         div.innerHTML = div.innerHTML + sub.endpoint;
         // var b = document.getElementsByTagName('body')[0];
         //b.appendChild(div);
         //alert(sub.endpoint);
       });
     });
   });
 }

有什么想法吗?

javascript google-chrome service-worker
3个回答
18
投票

您应该等待 Service Worker 被激活后再触发订阅。

使用 stateChange 侦听器来确定 Service Worker 是否处于活动状态

navigator.serviceWorker.register(workerFileName, {scope: "/"})
    .then(
    function (reg) {
        var serviceWorker;
        if (reg.installing) {
            serviceWorker = reg.installing;
            // console.log('Service worker installing');
        } else if (reg.waiting) {
            serviceWorker = reg.waiting;
            // console.log('Service worker installed & waiting');
        } else if (reg.active) {
            serviceWorker = reg.active;
            // console.log('Service worker active');
        }

        if (serviceWorker) {
            console.log("sw current state", serviceWorker.state);
            if (serviceWorker.state == "activated") {
                //If push subscription wasnt done yet have to do here
                console.log("sw already activated - Do watever needed here");
            }
            serviceWorker.addEventListener("statechange", function(e) {
                console.log("sw statechange : ", e.target.state);
                if (e.target.state == "activated") {
                    // use pushManger for subscribing here.
                    console.log("Just now activated. now we can subscribe for push notification")
                    subscribeForPushNotification(reg);
                }
            });
        }
    },
    function (err) {
        console.error('unsuccessful registration with ', workerFileName, err);
    }
);

7
投票

您可以通过检查 Service Worker 状态来解决此问题。仅当 Service Worker 处于活动状态时才执行您的操作。

navigator.serviceWorker.register('sw.js').then(function(reg) {
 if(reg.installing) {
        console.log('Service worker installing');
    } else if(reg.waiting) {
        console.log('Service worker installed');
    } else if(reg.active) {
        console.log('Service worker active');
    }
 // Include below mentioned validations
}

检查是否支持推送通知

 // Check if push messaging is supported  
    if (!('PushManager' in window)) {  
       console.log('Push messaging isn\'t supported.');  
       return;  
     }
   //
   if (Notification.permission === 'denied') {  
      console.log('The user has blocked notifications.');  
      return;  
   }

这两项检查后即可实现您的功能。

navigator.serviceWorker.ready.then(function(reg) {  .... })

希望这有帮助


0
投票

在我的场景中,我遇到了类似的问题,第一次尝试订阅推送通知时出现错误

Subscription failed - no active Service Worker
。发生这种情况是因为 Service Worker 尚未完全激活。第二次尝试成功了,因为 Service Worker 已经处于活动状态。

以下是调整代码来解决此问题的方法:

  1. 等待 Service Worker 准备就绪: 为了确保 Service Worker 在订阅之前完全激活,您应该等待 Service Worker 准备好。

  2. 实施步骤:

    firebase-messaging-sw.js
    (确保您的应用正确注册并使用此文件):

    importScripts("https://www.gstatic.com/firebasejs/9.22.0/firebase-app-compat.js");
    importScripts("https://www.gstatic.com/firebasejs/9.22.0/firebase-messaging-compat.js");
    
    const firebaseConfig = {
        /* Your config */
    };
    
    firebase.initializeApp(firebaseConfig);
    const messaging = firebase.messaging();
    
    self.addEventListener("install", (event) => {
        console.log("Service worker installed");
    });
    
    self.addEventListener("activate", (event) => {
        console.log("Service worker activated");
    });
    

    messaging-init-sw.js
    (初始化Firebase并请求权限的主文件):

    import { initializeApp } from "firebase/app";
    import { getMessaging, getToken, onMessage } from "firebase/messaging";
    
    const firebaseConfig = {
        /* Your config */
    };
    
    const app = initializeApp(firebaseConfig);
    const messaging = getMessaging(app);
    
    export async function requestPermission(callback) {
        try {
            const permission = await Notification.requestPermission();
            if (permission === "granted") {
                if ("serviceWorker" in navigator) {
                    try {
                        // Register the Service Worker
                        const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js');
    
                        // Wait for the Service Worker to be ready
                        await navigator.serviceWorker.ready;
    
                        // Perform your custom actions here
                        // For example, getting a device token:
                        // const deviceToken = await getToken(messaging, {
                        //     vapidKey: "YOUR_VAPID_KEY",
                        //     serviceWorkerRegistration: registration,
                        // });
    
                        // if (deviceToken) {
                        //     callback(deviceToken);
                        // } else {
                        //     console.log("No registration token available.");
                        // }
    
                        // Replace the above with your own logic
    
                    } catch (error) {
                        console.error("Error setting up Service Worker or getting token:", error);
                    }
                } else {
                    console.log("Service workers are not supported in this browser.");
                }
            } else {
                console.log("Unable to get permission to notify.");
            }
        } catch (error) {
            console.error("An error occurred while requesting permission:", error);
        }
    }
    

    Login.vue
    (初始化Firebase并请求权限的主文件):

    <script>
    import { getMessaging, isSupported } from "firebase/messaging";
    
    export default {
        name: "YourComponent",
        async mounted() {
            try {
                if (await isSupported()) {
                    const messaging = getMessaging();
                    console.log("Firebase Messaging is supported and initialized.");
                } else {
                    console.warn("Firebase Messaging is not supported in this browser.");
                }
            } catch (error) {
                console.error("Error initializing Firebase Messaging:", error);
            }
        },
    };
    </script>
    

说明:

  • 确保准备就绪: 代码注册 Service Worker 并在尝试订阅之前使用
    navigator.serviceWorker.ready
    等待其准备就绪。
  • 错误处理:
    .catch
    块处理过程中可能发生的错误。

通过实施这些更改,您可以确保 Service Worker 在订阅之前已完全准备好,这应该可以解决您遇到的错误。

© www.soinside.com 2019 - 2024. All rights reserved.