我有以下代码注册了服务人员,并要求用户允许通知。用户允许serviceWorkerRegistration.pushManager.getSubscription()
返回的承诺为null
的推送通知后出现错误。当我关闭浏览器并再次强制执行此函数调用时,它将正常工作而不会出现错误。我不明白为什么。这是我的代码:
window.vapidPublicKey = new Uint8Array([4, 45, ...]);
if (navigator.serviceWorker) {
navigator.serviceWorker.register('/serviceworker.js')
.then(function(reg) {
console.log('Service worker change, registered the service worker');
});
}
// Otherwise, no push notifications :(
else {
console.error('Service worker is not supported in this browser');
}
navigator.serviceWorker.ready.then((serviceWorkerRegistration) => {
console.log("ready");
serviceWorkerRegistration.pushManager
.subscribe({
userVisibleOnly: true,
applicationServerKey: window.vapidPublicKey
});
});
// application.js
// Let's check if the browser supports notifications
if (!("Notification" in window)) {
console.error("This browser does not support notifications.");
}
// Let's check whether notification permissions have already been granted
else if (Notification.permission === "granted") {
console.log("Permission to receive notifications has been granted");
}
// Otherwise, we need to ask the user for permission
else if (Notification.permission !== 'denied') {
Notification.requestPermission(function (permission) {
// If the user accepts, let's create a notification
if (permission === "granted") {
console.log("Permission to receive notifications has been granted");
saveSubscriptionToDatabase();
}
});
}
function saveSubscriptionToDatabase(){
navigator.serviceWorker.ready
.then((serviceWorkerRegistration) => {
console.log(serviceWorkerRegistration.pushManager.getSubscription());
serviceWorkerRegistration.pushManager.getSubscription()
.then((subscription) => {
$.post("/users/save_subscription", { subscription: subscription.toJSON() });
});
});
}
错误:
Uncaught (in promise) TypeError: Cannot read property 'toJSON' of null
at serviceWorkerRegistration.pushManager.getSubscription.then
更新:
所以我添加了以下按钮:
<input type="button" onclick="saveSubscriptionToDatabase();" value="test">
只要我通过单击按钮调用函数,所有的JS和post请求都可以按预期方式工作,但是当我从检查权限状态的条件中调用该函数时,它仍然会像以前一样失败。
更新2:
我尝试从另一角度重新编写代码。
function registerServiceWorker() {
return navigator.serviceWorker.register('serviceworker.js')
.then(function(registration) {
console.log('Service worker successfully registered.');
return registration;
})
.catch(function(err) {
console.error('Unable to register service worker.', err);
});
}
function askPermission() {
return new Promise(function(resolve, reject) {
const permissionResult = Notification.requestPermission(function(result) {
resolve(result);
});
if (permissionResult) {
permissionResult.then(resolve, reject);
}
})
.then(function(permissionResult) {
if (permissionResult !== 'granted') {
throw new Error('We weren\'t granted permission.');
}
});
}
function subscribeUserToPush() {
return navigator.serviceWorker.register('serviceworker.js')
.then(function(registration) {
const subscribeOptions = {
userVisibleOnly: true,
applicationServerKey: new Uint8Array("key goes here")
};
return registration.pushManager.subscribe(subscribeOptions);
})
.then(function(pushSubscription) {
console.log("never called");
console.log('Received PushSubscription: ', JSON.stringify(pushSubscription));
return pushSubscription;
});
}
registerServiceWorker();
askPermission();
subscribeUserToPush();
我拥有subscribeUserToPush()
的{{1}}中命令链的最后一部分永远不会执行,也没有错误。我正在Chrome 67中对此进行测试。我很肯定会调用console.log("never called");
。
答案 0 :(得分:1)
因此,经过数小时的尝试,我终于弄清了这个问题,它很烦人。因此,每次调用navigator.serviceWorker.register('serviceworker.js')
时,都必须在文件名前加上/
。如果没有/
,服务人员就可以正常注册,但是获取订阅将失败。您在文档中找到的示例不包含/
。
因此,代码应如下所示:
navigator.serviceWorker.register('/serviceworker.js')
Tada现在可以工作了。...