推送事件

Matt Gaunt

到目前为止,我们已经介绍了如何订阅用户和发送推送消息。下一步是 在用户设备上接收此推送消息并显示通知 我们想要做的工作)。

推送事件

收到消息后,会在 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 Worker 和 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 会在显示通知后解析。

为了使此示例尽可能清晰,我将此 promise 分配给了 名为 promiseChain 的变量。然后将其传入 event.waitUntil()。我知道这是 非常冗长,但我已经看到了 误解了应向 waitUntil() 传递什么数据,或由于 promise 出错而传递什么数据 链。

一个更复杂的示例,其中包含针对数据的网络请求以及使用 可能如下所示:

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() 的函数, 在本示例中,我们可以假装将发出网络请求 分析服务提供商我们还将发出网络请求,获取 响应,并使用标题和响应数据显示通知 消息。

在这两个任务同时完成时,我们可以将 Service Worker 这些 promise 与 Promise.all() 结合使用。生成的 promise 会传递到 event.waitUntil() 中 这意味着浏览器会等到两个 promise 都完成后再检查通知 并终止 Service Worker。

我们之所以应该关注 waitUntil() 及其使用方式,是因为 开发者面临的常见问题是:如果 promise 链不正确 / 已损坏,Chrome 将会 显示此“默认”通知:

Chrome 中默认通知的图片

Chrome 仅会显示“此网站已在后台更新”。触发 收到推送消息后,Service Worker 中的推送事件没有显示 在传递给 event.waitUntil() 的 promise 完成后发出通知。

开发者遇到这一问题的主要原因是 经常调用 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()

在下一部分,我们将介绍如何设置通知样式, 我们可以展示哪些内容

下一步做什么

Codelab