Sử dụng Service Worker để quản lý thông báo

Kate Jeffreys
Kate Jeffreys

Trong lớp học lập trình này, bạn sẽ sử dụng một service worker để quản lý thông báo. Hướng dẫn ở đây giả định rằng bạn đã quen thuộc với các worker dịch vụ và những điều cơ bản về việc yêu cầu quyền gửi thông báo và gửi thông báo. Nếu bạn cần ôn tập lại về thông báo, hãy xem lớp học lập trình Bắt đầu sử dụng Notifications API. Để tìm hiểu thêm về trình chạy dịch vụ, hãy xem bài viết Giới thiệu về trình chạy dịch vụ của Matt Gaunt.

Làm quen với ứng dụng mẫu và mã khởi đầu

Bắt đầu bằng cách xem ứng dụng đang hoạt động trong thẻ Chrome mới:

  1. Nhấn tổ hợp phím `Control+Shift+J` (hoặc `Command+Option+J` trên máy Mac) để mở Công cụ cho nhà phát triển.
  2. Nhấp vào thẻ Bảng điều khiển.

  3. Đảm bảo rằng bạn đã chọn lựa chọn Info (Thông tin) trong trình đơn thả xuống Levels (Cấp độ) bên cạnh hộp Filter (Bộ lọc).

  4. Trong bảng điều khiển Công cụ cho nhà phát triển của ứng dụng đang hoạt động, bạn sẽ thấy một thông báo trên bảng điều khiển:

    TODO: Implement getRegistration().

    Đây là thông báo từ một hàm gốc mà bạn sẽ triển khai trong lớp học lập trình này.

Bây giờ, hãy xem mã của ứng dụng mẫu.

  1. Hãy xem public/index.js:

    • Có 4 phần giữ chỗ cho các hàm mà bạn sẽ triển khai: registerServiceWorker, getRegistration, unRegisterServiceWorkersendNotification.

    • Hàm requestPermission yêu cầu người dùng cấp quyền gửi thông báo. Nếu đã hoàn thành Lớp học lập trình Bắt đầu sử dụng Notifications API, bạn sẽ nhận thấy hàm requestPermission của lớp học này được dùng ở đây. Điểm khác biệt duy nhất là giờ đây, phương thức này cũng cập nhật giao diện người dùng sau khi giải quyết yêu cầu cấp quyền.

    • Hàm updateUI làm mới tất cả các nút và thông báo của ứng dụng.

    • Hàm initializePage thực hiện việc phát hiện tính năng cho khả năng của service worker trong trình duyệt và cập nhật giao diện người dùng của ứng dụng.

    • Tập lệnh này sẽ chờ cho đến khi trang tải xong rồi mới khởi động.

  2. Mở public/service-worker.js.

    Như tên gọi, bạn sẽ thêm mã vào ứng dụng để đăng ký tệp này làm worker dịch vụ.

    Mặc dù ứng dụng chưa sử dụng tệp này, nhưng tệp này chứa một số mã khởi động sẽ in một thông báo vào bảng điều khiển khi trình chạy dịch vụ được kích hoạt.

    Bạn sẽ thêm mã vào public/service-worker.js để xử lý thông báo khi trình chạy dịch vụ nhận được thông báo.

Đăng ký trình chạy dịch vụ

Ở bước này, bạn sẽ viết mã chạy khi người dùng nhấp vào Register service worker (Đăng ký trình chạy dịch vụ) trong giao diện người dùng của ứng dụng. Mã này sẽ đăng ký public/service-worker.js làm worker dịch vụ.

  1. Mở public/index.js. Thay thế hàm registerServiceWorker bằng mã sau:

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

    Xin lưu ý rằng registerServiceWorker sử dụng khai báo async function để xử lý các promise một cách thuận tiện hơn. Thao tác này cho phép bạn await giá trị đã phân giải của một Promise. Ví dụ: hàm ở trên sẽ đợi kết quả đăng ký một worker dịch vụ trước khi cập nhật giao diện người dùng. Hãy xem await trên MDN để biết thêm thông tin.

  2. Giờ đây, người dùng có thể đăng ký một worker dịch vụ, bạn có thể tham chiếu đến đối tượng đăng ký worker dịch vụ. Trong public/index.js, hãy thay thế hàm getRegistration bằng đoạn mã sau:

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

    Hàm ở trên sử dụng Service Worker API để lấy thông tin đăng ký service worker hiện tại (nếu có). Điều này giúp việc tham chiếu đến quy trình đăng ký worker dịch vụ trở nên thuận tiện hơn một chút.

  • Để hoàn tất chức năng đăng ký trình chạy dịch vụ, hãy thêm mã để huỷ đăng ký trình chạy dịch vụ. Thay thế hàm unRegisterServiceWorker bằng mã sau:

    // 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();
    }
    

Trong thẻ mà bạn đang xem ứng dụng trực tiếp, hãy tải lại trang. Các nút Register service worker (Đăng ký trình chạy dịch vụ) và Unregister service worker (Huỷ đăng ký trình chạy dịch vụ) hiện đã hoạt động.

Gửi thông báo đến service worker

Trong bước này, bạn sẽ viết mã sẽ chạy khi người dùng nhấp vào Gửi thông báo trong giao diện người dùng của ứng dụng. Mã này sẽ tạo một thông báo, kiểm tra xem một worker dịch vụ đã được đăng ký hay chưa, sau đó gửi thông báo đến worker dịch vụ bằng phương thức postMessage.

Mở public/index.js và thay thế hàm sendNotification bằng mã sau:

// 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.');
    }
  }
}

Sau đây là những gì mã đó thực hiện:

  • sendNotification là một hàm không đồng bộ, vì vậy, bạn có thể dùng await để tham chiếu đến việc đăng ký trình chạy dịch vụ.

  • Phương thức postMessage của worker dịch vụ sẽ gửi dữ liệu từ ứng dụng đến worker dịch vụ. Hãy xem tài liệu của MDN về postMessage để biết thêm thông tin.

  • Mã này kiểm tra sự hiện diện của thuộc tính navigator.serviceWorker.controller trước khi cố gắng truy cập vào hàm postMessage. navigator.serviceWorker.controller sẽ là null nếu không có trình chạy dịch vụ nào đang hoạt động hoặc nếu trang đã được làm mới bắt buộc (Shift+Tải lại). Hãy xem tài liệu về bộ điều khiển ServiceWorker trên MDN để biết thêm thông tin.

Xử lý thông báo trong worker dịch vụ

Trong bước này, bạn sẽ viết mã trong trình chạy dịch vụ để xử lý các thông báo được đăng lên trình chạy dịch vụ và hiển thị thông báo cho người dùng.

Mở public/service-worker.js. Thêm đoạn mã sau vào cuối tệp:

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

Sau đây là phần giải thích ngắn gọn:

  • self là một tham chiếu đến chính service worker.

  • Mặc dù hiện tại service worker xử lý việc hiển thị thông báo, nhưng giao diện người dùng chính của ứng dụng vẫn chịu trách nhiệm nhận quyền thông báo từ người dùng. Nếu quyền không được cấp, lời hứa do showNotification trả về sẽ bị từ chối. Đoạn mã trên sử dụng khối catch để tránh lỗi từ chối Promise chưa được phát hiện và xử lý lỗi này một cách hiệu quả hơn.

Hãy chuyển sang lớp học lập trình tiếp theo trong loạt bài này: Tạo một máy chủ thông báo đẩy.