至此,我们介绍了如何订阅用户和发送推送消息。下一步是在用户设备上接收此推送消息并显示通知(以及执行我们可能想要执行的任何其他工作)。
推送事件
收到消息后,系统会在 Service Worker 中分派推送事件。
用于设置推送事件监听器的代码应该与使用 JavaScript 编写的任何其他事件监听器非常相似:
self.addEventListener('push', function(event) {
if (event.data) {
console.log('This push event has data: ', event.data.text());
} else {
console.log('This push event has no data.');
}
});
对于大多数刚接触 Service Worker 的开发者来说,此代码中最奇怪的一点是 self
变量。self
通常用于 Web Worker(即 Service Worker)。self
是指全局范围,类似于网页中的 window
。但对于 Web 工作器和 Service Worker,self
是指 worker 本身。
在上面的示例中,可以将 self.addEventListener()
视为向 Service Worker 本身添加事件监听器。
在推送事件示例中,我们会检查是否有任何数据,并在控制台中输出一些内容。
您还可以通过其他方式解析推送事件中的数据:
// Returns string
event.data.text()
// Parses data as JSON string and returns an Object
event.data.json()
// Returns blob of data
event.data.blob()
// Returns an arrayBuffer
event.data.arrayBuffer()
大多数人使用 json()
或 text()
,具体取决于他们对应用的要求。
此示例演示了如何添加推送事件监听器以及如何访问数据,但它缺少两项非常重要的功能。它未显示通知,也没有使用 event.waitUntil()
。
等待至
关于 Service Worker 的一个注意事项是,您几乎无法控制 Service Worker 代码的运行时间。浏览器决定何时将其唤醒以及何时终止。告知浏览器“嘿,我超级忙着做重要事情”的唯一方式就是将 promise 传递到 event.waitUntil()
方法中。这样,浏览器将保持 Service Worker 运行,直到您传入的 promise 结束。
对于推送事件,还有一个额外的要求是,您必须在传入的 promise 得到解决之前显示通知。
下面是一个显示通知的基本示例:
self.addEventListener('push', function(event) {
const promiseChain = self.registration.showNotification('Hello, World.');
event.waitUntil(promiseChain);
});
调用 self.registration.showNotification()
是向用户显示通知的方法,并返回一个会在显示通知后解析的 promise。
为使此示例尽可能清晰明了,我已将此 promise 分配给名为 promiseChain
的变量。然后将其传入 event.waitUntil()
。我知道这段代码是非常冗长的,但由于对应传入 waitUntil()
的内容误解或 promise 链的损坏,导致出现了许多问题。
下面是一个更复杂的示例,它包含数据网络请求并使用 Analytics 跟踪推送事件:
self.addEventListener('push', function(event) {
const analyticsPromise = pushReceivedTracking();
const pushInfoPromise = fetch('/api/get-more-data')
.then(function(response) {
return response.json();
})
.then(function(response) {
const title = response.data.userName + ' says...';
const message = response.data.message;
return self.registration.showNotification(title, {
body: message
});
});
const promiseChain = Promise.all([
analyticsPromise,
pushInfoPromise
]);
event.waitUntil(promiseChain);
});
在这里,我们要调用一个会返回 promise pushReceivedTracking()
的函数,在本示例中,我们可以假装会向我们的分析服务提供方发出网络请求。我们还发出网络请求,获得响应并使用通知标题和消息的响应数据显示通知。
通过将这些 promise 与 Promise.all()
结合使用,我们可以确保 Service Worker 在这两项任务都完成时保持活跃状态。生成的 promise 会传递到 event.waitUntil()
,这意味着浏览器会等到两个 promise 完成后再检查是否已显示通知并终止 Service Worker。
我们应该对 waitUntil()
及其使用方法感到担忧的原因是,开发者面临的一个最常见的问题是,当 promise 链不正确 / 损坏时,Chrome 会显示此“默认”通知:
![Chrome 中默认通知的图片](https://web.developers.google.cn/static/articles/push-notifications-handling-messages/image/an-image-the-default-not-ec0a0feda0315.png?authuser=6&hl=da)
收到推送消息但 Service Worker 中的推送事件不在传递给 event.waitUntil()
的 promise 完成后,Chrome 只会显示“此网站已在后台更新”通知。
开发者被此困扰的主要原因是,他们的代码通常会调用 self.registration.showNotification()
,但并未对其返回的 promise 执行任何操作。此操作间歇性会导致显示默认通知。例如,我们可以在上面的示例中移除 self.registration.showNotification()
的返回值,否则可能会看到此通知。
self.addEventListener('push', function(event) {
const analyticsPromise = pushReceivedTracking();
const pushInfoPromise = fetch('/api/get-more-data')
.then(function(response) {
return response.json();
})
.then(function(response) {
const title = response.data.userName + ' says...';
const message = response.data.message;
self.registration.showNotification(title, {
body: message
});
});
const promiseChain = Promise.all([
analyticsPromise,
pushInfoPromise
]);
event.waitUntil(promiseChain);
});
您可以发现,很容易错过。
请注意,如果您看到该通知,请检查您的 promise 链和 event.waitUntil()
。
在下一部分中,我们将了解如何设置通知样式以及可以显示哪些内容。