至此,我们已经介绍了如何让用户订阅以及如何发送推送消息。下一步是在用户设备上接收此推送消息并显示通知(以及执行我们可能想要执行的任何其他工作)。
推送事件
收到消息后,系统会在 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 也是一种 Web Worker)。self 是指全局范围,有点像网页中的 window。但对于 Web Worker 和 Service Worker,self 是指工作器本身。
在上面的示例中,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 会在通知显示后解析。
为了尽可能清楚地展示此示例,我已将此 promise 分配给名为 promiseChain 的变量。然后,此值会被传递到 event.waitUntil()。我知道这非常冗长,但我已经看到许多问题,这些问题都是由于误解了应该传递到 waitUntil() 中的内容或由于 promise 链损坏而导致的。
一个更复杂的示例(包含对数据的网络请求以及使用 Google 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 会显示以下“默认”通知:
只有在收到推送消息,且在传递给 event.waitUntil() 的 promise 完成后,Service Worker 中的推送事件未显示通知时,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()。
在下一部分中,我们将了解如何设置通知样式以及可以显示哪些内容。
下一步做什么
- Web 推送通知概览
- 推送的工作原理
- 为用户订阅
- 权限用户体验
- 使用 Web 推送库发送消息
- Web 推送协议
- 处理推送事件
- 显示通知
- 通知行为
- 常见通知模式
- 推送通知常见问题解答
- 常见问题和报告错误