使用 Service Worker 管理通知

Kate Jeffreys
Kate Jeffreys

在此 Codelab 中,您将使用 Service Worker 来管理通知。本说明假定您已熟悉服务工件以及请求通知权限和发送通知的基础知识。如果您需要回顾一下通知相关知识,请参阅 Notifications API 使用入门 Codelab。如需详细了解 Service Worker,请参阅 Matt Gaunt 的 Service Worker 简介

系统会自动屏蔽嵌入的 Glitch 应用发送的通知,因此您将无法在此页面上预览该应用。请改为执行以下操作:

  1. 点击 Remix to Edit 即可修改项目。
  2. 如需预览网站,请按 View App(查看应用)。然后按 Fullscreen(全屏)全屏

Glitch 应该会在新标签页中打开。

在完成此 Codelab 的过程中,请更改此页面中嵌入的 Glitch 中的代码。刷新包含实时应用的新标签页,即可查看更改。

熟悉示例应用和起始代码

首先,查看新 Chrome 标签页中的实时应用:

  1. 按 `Control+Shift+J`(在 Mac 上为 `Command+Option+J`)打开 DevTools。
  2. 点击控制台标签页。

  3. 确保已在 Filter 框旁边的 Levels 下拉菜单中选择 Info 选项。

  4. 在正式版应用的开发者工具控制台中,您应该会看到一条控制台消息:

    TODO: Implement getRegistration()

    这是您将在此 Codelab 中实现的函数桩发送的消息。

现在,我们来看看本页面上的嵌入式 Glitch 中的示例应用代码。

  1. 在嵌入式 Glitch 中,查看 public/index.js

    • 您将实现的函数有四个桩:registerServiceWorkergetRegistrationunRegisterServiceWorkersendNotification

    • requestPermission 函数会请求用户授予发送通知的权限。如果您已完成 “开始使用 Notifications API”Codelab,就会发现此处使用了该 Codelab 中的 requestPermission 函数。唯一的区别在于,现在还会在解析权限请求后更新界面。

    • updateUI 函数会刷新应用的所有按钮和消息。

    • initializePage 函数会在浏览器中对 Service Worker 功能执行功能检测,并更新应用界面。

    • 脚本会等待页面加载完毕,然后对其进行初始化。

  2. 在嵌入式 Glitch 中,打开 public/service-worker.js

    顾名思义,您需要向应用添加代码,以将此文件注册为 Service Worker

    尽管该文件尚未被应用使用,但它包含一些起始代码,这些代码将在激活 Service Worker 时向控制台输出消息。

    您将向 public/service-worker.js 添加代码,以便在服务工作线程收到通知时处理通知。

注册 Service Worker

在此步骤中,您将编写在用户点击应用界面中的 Register service worker 时运行的代码。此代码将 public/service-worker.js 注册为服务工作器。

  1. 在嵌入式 Glitch 编辑器中,打开 public/index.js。将 registerServiceWorker 函数替换为以下代码:

    // Use the Service Worker API to register a service worker.
    async
    function registerServiceWorker() {
      await navigator
    .serviceWorker.register('./service-worker.js')
      updateUI
    ();
    }

    请注意,registerServiceWorker 使用 async function 声明来简化对 promise 的处理。这样,您就可以 await Promise 的解析值。例如,上述函数会等待注册 Service Worker 的结果,然后再更新界面。如需了解详情,请参阅 MDN 上的 await

  2. 现在,用户可以注册服务工作线程,您可以获取对服务工作线程注册对象的引用。在 public/index.js 中,将 getRegistration 函数替换为以下代码:

    // Get the current service worker registration.
    function getRegistration() {
     
    return navigator.serviceWorker.getRegistration();
    }

    上述函数使用 Service Worker API 获取当前的 Service Worker 注册(如果存在)。它会更方便地获取对 Service Worker 注册的引用。

  • 如需完成服务工件注册功能,请添加代码以取消注册服务工件。将 unRegisterServiceWorker 函数替换为以下代码:

    // Unregister a service worker, then update the UI.
    async
    function unRegisterServiceWorker() {
     
    // Get a reference to the service worker registration.
      let registration
    = await getRegistration();
     
    // Await the outcome of the unregistration attempt
     
    // so that the UI update is not superceded by a
     
    // returning Promise.
      await registration
    .unregister();
      updateUI
    ();
    }

在您当前查看应用的标签页中,重新加载页面。Register Service WorkerUnregister Service Worker 按钮现在应该可以正常使用了。

向 Service Worker 发送通知

在此步骤中,您将编写在用户点击应用界面中的发送通知时运行的代码。此代码将创建通知、检查是否已注册服务工作器,然后使用其 postMessage 方法将通知发送到服务工作器。

在嵌入式 Glitch 编辑器中,打开 public/index.js 并将 sendNotification 函数替换为以下代码:

// Create and send a test notification to the service worker.
async
function sendNotification() {
 
// Use a random number as part of the notification data
 
// (so you can tell the notifications apart during testing!)
  let randy
= Math.floor(Math.random() * 100);
  let notification
= {
    title
: 'Test ' + randy,
    options
: { body: 'Test body ' + randy }
 
};
 
// Get a reference to the service worker registration.
  let registration
= await getRegistration();
 
// Check that the service worker registration exists.
 
if (registration) {
   
// Check that a service worker controller exists before
   
// trying to access the postMessage method.
   
if (navigator.serviceWorker.controller) {
      navigator
.serviceWorker.controller.postMessage(notification);
   
} else {
      console
.log('No service worker controller found. Try a soft reload.');
   
}
 
}
}

该代码的作用如下:

  • sendNotification 是一个异步函数,因此您可以使用 await 获取对 Service Worker 注册的引用。

  • Service Worker 的 postMessage 方法将数据从应用发送到 Service Worker。如需了解详情,请参阅 MDN 文档中的 postMessage 部分。

  • 该代码会先检查 navigator.serviceWorker.controller 属性是否存在,然后再尝试访问 postMessage 函数。如果没有处于活动状态的 Service Worker,或者网页已被强制刷新 (Shift+Reload),navigator.serviceWorker.controller 将为 null。如需了解详情,请参阅 MDN 上的 ServiceWorker 控制器文档

在 Service Worker 中处理通知

在此步骤中,您将在服务工作器中编写代码,用于处理向其发布的消息并向用户显示通知。

在内嵌的 Glitch 编辑器中,打开 public/service-worker.js。将以下代码添加到文件末尾:

// Show notification when received
self
.addEventListener('message', (event) => {
  let notification
= event.data;
  self
.registration.showNotification(
    notification
.title,
    notification
.options
 
).catch((error) => {
    console
.log(error);
 
});
});

下面是简要说明:

  • self 是指向服务工作器本身的引用。

  • 虽然现在服务工件会处理显示通知,但主应用界面仍负责从用户获取通知权限。如果未授予权限,showNotification 返回的 promise 将被拒绝。上述代码使用 catch 块来避免未捕获的 Promise 拒绝错误,并更妥当地处理此错误。

如果您遇到困难,请参阅 glitch.com/edit/#!/codelab-notifications-service-worker-completed,获取已完成的代码。

继续学习本系列的下一个 Codelab:构建推送通知服务器