首页 文章

在注册服务工作者之前尝试运行获取功能 .

提问于
浏览
1

我正在尝试运行一个获取函数,它将从我的服务器获取一些值 . 但由于某种原因,服务工作者的注册首先触发,并且其“app_key”未定义,导致它抛出异常 . 这似乎是一种竞争条件,我不知道如何解决 .

我不确定如何将值分配给变量以确保它们可被其他函数看到 . 任何建议,将不胜感激 .

project_url = window.location.hostname;

var vapi_key;
var app_key;
var pushSub;
var end_point = "https://" + project_url + "/push/subscribe/create";

(() =>  {
    return fetch ("https://" + project_url + "/push/get_public_key"
    ).then((response) => {
        return response.json();
    })
    .then((responseJSON) => {
        vapi_key = responseJSON;
        urlBase64ToUint8Array(vapi_key);
        console.log("VAPI_KEY: ", vapi_key);
        console.log("APP_KEY: ", app_key)
    }).catch((err) => {
        console.log('Fetch Error : ', err);
    });
})();


(() => {
    return new Promise((resolve, reject) => {
        const permissionResult = Notification.requestPermission((result) => {
            resolve(result);
        });

        if (permissionResult) {
            permissionResult.then(resolve, reject);
        }
    })
        .then((permissionResult) => {
            if (permissionResult !== 'granted') {
                throw new Error('We weren\'t granted permission.');
            }
        });
})();

(() => {
    if ('serviceWorker' in navigator && 'PushManager' in window) {
        navigator.serviceWorker.register('/sw_bundle.js')
            .then((registration) => {
                let subscribeOptions = {
                    userVisibleOnly: true,
                    applicationServerKey: app_key,
                };

                return registration.pushManager.subscribe(subscribeOptions);
            })
            .then((pushSubscription) => {
                console.log('Received PushSubscription: ', JSON.stringify(pushSubscription));
                const subscriptionObject = {
                    endpoint: pushSubscription.endpoint,
                    keys: {
                        p256dh: pushSubscription.keys['p256dh'],
                        auth: pushSubscription.keys['auth']
                    }
                };
                sendSubscriptionToBackEnd(subscriptionObject);
                return pushSubscription;
            });
    } else {
        console.warn('Push messaging is not supported');
    }
})();

function urlBase64ToUint8Array(base64String) {
    const padding = '='.repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding)
        .replace(/\-/g, '+')
        .replace(/_/g, '/');
    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);
    for (var i = 0; i < rawData.length; ++i) {
        outputArray[i] = rawData.charCodeAt(i);
    }
    app_key = outputArray;
}

1 回答

  • 1

    我不确定你为什么期望这个工作 . 特别是为什么你使用IIFE来创建承诺 . 无论如何,如果你想要一个承诺被链接到另一个承诺,你需要通过在第一个承诺的 .then 调用中创建第二个承诺来明确这个 . 这是一个例子:

    const createPromiseA = () => new Promise((resolve) => {
    window.setTimeout(() => { console.log('promiseA'); resolve(); }, 2000);
    });
    
    const createPromiseB = () => new Promise((resolve) => {
    window.setTimeout(() => { console.log('promiseB'); resolve(); }, 3000);
    });
    
    createPromiseA().then(createPromiseB);
    

    在您的情况下,您需要执行以下操作:

    const fetchKeys = () => fetch ("https://" + project_url + "/push/get_public_key"
        ).then((response) => {
            return response.json();
        })
        .then((responseJSON) => {
            vapi_key = responseJSON;
            urlBase64ToUint8Array(vapi_key);
            console.log("VAPI_KEY: ", vapi_key);
            console.log("APP_KEY: ", app_key)
        }).catch((err) => {
            console.log('Fetch Error : ', err);
        });
    
    const registerWorker = () => {
        if ('serviceWorker' in navigator && 'PushManager' in window) {
            navigator.serviceWorker.register('/sw_bundle.js')
                .then((registration) => {
                    let subscribeOptions = {
                        userVisibleOnly: true,
                        applicationServerKey: app_key,
                    };
    
                    return registration.pushManager.subscribe(subscribeOptions);
                })
                .then((pushSubscription) => {
                    console.log('Received PushSubscription: ', JSON.stringify(pushSubscription));
                    const subscriptionObject = {
                        endpoint: pushSubscription.endpoint,
                        keys: {
                            p256dh: pushSubscription.keys['p256dh'],
                            auth: pushSubscription.keys['auth']
                        }
                    };
                    sendSubscriptionToBackEnd(subscriptionObject);
                    return pushSubscription;
                });
        } else {
            return Promise.reject('Push messaging is not supported');
        }
    };
    
    // …
    
    fetchKeys().then(registerWorker)
    .then(() => { console.log('(!) Success!'); });
    

    NOTE: 利用IIFE的更好的方法是将整个脚本包装在一个函数中并执行它 . 这会将变量绑定到函数的局部范围,而不会暴露它们 . 即做类似的事情:

    (() => {
        project_url = window.location.hostname;
    
        var vapi_key;
        var app_key;
        var pushSub;
        var end_point = "https://" + project_url + "/push/subscribe/create";
    
        // ...
    
        const fetchKeys = () => { ... } ;
        const registerWorker = () => { ... } ;
    
        // ...
    
        fetchKeys().then(registerWorker)
        .then(() => { console.log('(!) Success!'); });
    
    })();
    

相关问题