Xây dựng trải nghiệm tìm kiếm linh hoạt với Workbox

Lớp học lập trình này cho bạn biết cách triển khai trải nghiệm tìm kiếm linh hoạt bằng Workbox. Ứng dụng minh hoạ mà ứng dụng này sử dụng chứa một hộp tìm kiếm gọi một điểm cuối máy chủ và chuyển hướng người dùng đến một trang HTML cơ bản.

Đo

Trước khi thêm các tính năng tối ưu hoá, bạn nên phân tích trạng thái hiện tại của ứng dụng.

  • Nhấp vào Phối lại để chỉnh sửa để có thể chỉnh sửa dự án.
  • Để xem trước trang web, hãy nhấn vào Xem ứng dụng. Sau đó, nhấn vào biểu tượng Màn hình toàn cảnh toàn màn hình.

Trong thẻ mới vừa mở ra, hãy kiểm tra cách trang web hoạt động khi không có kết nối mạng:

  1. Nhấn tổ hợp phím `Ctrl+Shift+J` (hoặc `Command+Option+J` trên máy Mac) để mở DevTools.
  2. Nhấp vào thẻ Mạng.
  3. Mở Công cụ của Chrome cho nhà phát triển rồi chọn bảng điều khiển Mạng.
  4. Trong danh sách thả xuống về Throttling (Giới hạn), hãy chọn Offline (Khi không có mạng).
  5. Trong ứng dụng minh hoạ, hãy nhập một cụm từ tìm kiếm, sau đó nhấp vào nút Tìm kiếm.

Trang lỗi trình duyệt tiêu chuẩn sẽ xuất hiện:

Ảnh chụp màn hình giao diện người dùng ngoại tuyến mặc định trên trình duyệt.

Cung cấp phản hồi dự phòng

Trình chạy dịch vụ chứa mã để thêm trang ngoại tuyến vào danh sách lưu vào bộ nhớ đệm trước, vì vậy, trang này luôn có thể được lưu vào bộ nhớ đệm tại sự kiện install của trình chạy dịch vụ.

Thông thường, bạn cần hướng dẫn Workbox thêm tệp này vào danh sách bộ nhớ đệm trước tại thời điểm xây dựng, bằng cách tích hợp thư viện với công cụ xây dựng mà bạn lựa chọn (ví dụ: webpack hoặc gulp).

Để đơn giản hoá, chúng tôi đã thực hiện việc này cho bạn. Mã sau đây tại public/sw.js sẽ thực hiện việc đó:

const FALLBACK_HTML_URL = '/index_offline.html';

workbox.precaching.precacheAndRoute([FALLBACK_HTML_URL]);

Tiếp theo, hãy thêm mã để sử dụng trang ngoại tuyến làm phản hồi dự phòng:

  1. Để xem nguồn, hãy nhấn vào Xem nguồn.
  2. Thêm mã sau vào cuối public/sw.js:
workbox.routing.setDefaultHandler(new workbox.strategies.NetworkOnly());

workbox.routing.setCatchHandler(({event}) => {
  switch (event.request.destination) {
    case 'document':
      return caches.match(FALLBACK_HTML_URL);
      break;
    default:
      return Response.error();
  }
});

Mã này thực hiện những việc sau:

  • Xác định chiến lược Chỉ mạng mặc định sẽ áp dụng cho tất cả các yêu cầu.
  • Khai báo trình xử lý lỗi toàn cục bằng cách gọi workbox.routing.setCatchHandler() để quản lý các yêu cầu không thành công. Khi yêu cầu là về tài liệu, hệ thống sẽ trả về một trang HTML dự phòng ở chế độ ngoại tuyến.

Cách kiểm thử chức năng này:

  1. Quay lại thẻ khác đang chạy ứng dụng của bạn.
  2. Đặt danh sách thả xuống Throttling (Giới hạn) về trạng thái Online (Trực tuyến).
  3. Nhấn nút Quay lại của Chrome để quay lại trang tìm kiếm.
  4. Đảm bảo rằng bạn đã tắt hộp đánh dấu Tắt bộ nhớ đệm trong Công cụ cho nhà phát triển.
  5. Nhấn và giữ nút Reload (Tải lại) của Chrome rồi chọn Empty cache and key nạp (Làm trống bộ nhớ đệm và tải lại cứng) để đảm bảo trình chạy dịch vụ của bạn được cập nhật.
  6. Đặt lại danh sách thả xuống Throttling (Giới hạn) về Offline (Ngoại tuyến).
  7. Nhập cụm từ tìm kiếm rồi nhấp lại vào nút Tìm kiếm.

Trang HTML dự phòng sẽ xuất hiện:

Ảnh chụp màn hình về trải nghiệm người dùng tuỳ chỉnh khi không có mạng trong trình duyệt.

Yêu cầu cấp quyền gửi thông báo

Để đơn giản, trang ngoại tuyến tại views/index_offline.html đã chứa mã để yêu cầu quyền gửi thông báo trong khối tập lệnh ở dưới cùng:

function requestNotificationPermission(event) {
  event.preventDefault();

  Notification.requestPermission().then(function (result) {
    showOfflineText(result);
  });
}

Mã này thực hiện những việc sau:

  • Khi người dùng nhấp vào đăng ký nhận thông báo, hàm requestNotificationPermission() sẽ được gọi (gọi Notification.requestPermission()) để hiển thị lời nhắc cấp quyền mặc định của trình duyệt. Lời hứa sẽ được thực hiện bằng quyền do người dùng chọn, có thể là granted, denied hoặc default.
  • Truyền quyền đã phân giải đến showOfflineText() để hiển thị văn bản thích hợp cho người dùng.

Duy trì các truy vấn ngoại tuyến và thử lại khi có kết nối mạng

Tiếp theo, hãy triển khai tính năng Đồng bộ hoá ở chế độ nền của Workbox để duy trì các truy vấn ngoại tuyến, nhờ đó, bạn có thể thử lại khi trình duyệt phát hiện thấy kết nối đã trở lại.

  1. Mở public/sw.js để chỉnh sửa.
  2. Thêm mã sau vào cuối tệp:
const bgSyncPlugin = new workbox.backgroundSync.Plugin('offlineQueryQueue', {
  maxRetentionTime: 60,
  onSync: async ({queue}) => {
    let entry;
    while ((entry = await queue.shiftRequest())) {
      try {
        const response = await fetch(entry.request);
        const cache = await caches.open('offline-search-responses');
        const offlineUrl = `${entry.request.url}&notification=true`;
        cache.put(offlineUrl, response);
        showNotification(offlineUrl);
      } catch (error) {
        await this.unshiftRequest(entry);
        throw error;
      }
    }
  },
});

Mã này thực hiện những việc sau:

  • workbox.backgroundSync.Plugin chứa logic để thêm các yêu cầu không thành công vào hàng đợi để có thể thử lại sau. Các yêu cầu này sẽ được lưu trữ trong IndexedDB.
  • maxRetentionTime cho biết khoảng thời gian có thể thử lại một yêu cầu. Trong trường hợp này, chúng ta đã chọn 60 phút (sau đó, dữ liệu này sẽ bị loại bỏ).
  • onSync là phần quan trọng nhất của mã này. Lệnh gọi lại này sẽ được gọi khi kết nối trở lại để truy xuất các yêu cầu đã xếp hàng rồi tìm nạp từ mạng.
  • Phản hồi mạng được thêm vào bộ nhớ đệm offline-search-responses, thêm tham số truy vấn &notification=true để có thể chọn mục nhập bộ nhớ đệm này khi người dùng nhấp vào thông báo.

Để tích hợp tính năng đồng bộ hoá ở chế độ nền với dịch vụ của bạn, hãy xác định chiến lược NetworkOnly cho các yêu cầu đến URL tìm kiếm (/search_action) và truyền bgSyncPlugin đã xác định trước đó. Thêm mã sau vào cuối public/sw.js:

const matchSearchUrl = ({url}) => {
  const notificationParam = url.searchParams.get('notification');
  return url.pathname === '/search_action' && !(notificationParam === 'true');
};

workbox.routing.registerRoute(
  matchSearchUrl,
  new workbox.strategies.NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
);

Thao tác này sẽ yêu cầu Workbox luôn truy cập mạng và khi yêu cầu không thành công, hãy sử dụng logic đồng bộ hoá ở chế độ nền.

Tiếp theo, hãy thêm mã sau vào cuối public/sw.js để xác định chiến lược lưu vào bộ nhớ đệm cho các yêu cầu đến từ thông báo. Sử dụng chiến lược CacheFirst để có thể phân phát các tệp đó từ bộ nhớ đệm.

const matchNotificationUrl = ({url}) => {
  const notificationParam = url.searchParams.get('notification');
  return (url.pathname === '/search_action' && (notificationParam === 'true'));
};

workbox.routing.registerRoute(matchNotificationUrl,
  new workbox.strategies.CacheFirst({
     cacheName: 'offline-search-responses',
  })
);

Cuối cùng, hãy thêm mã để hiển thị thông báo:

function showNotification(notificationUrl) {
  if (Notification.permission) {
     self.registration.showNotification('Your search is ready!', {
        body: 'Click to see you search result',
        icon: '/img/workbox.jpg',
        data: {
           url: notificationUrl
        }
     });
  }
}

self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  event.waitUntil(
     clients.openWindow(event.notification.data.url)
  );
});

Kiểm thử tính năng

  1. Quay lại thẻ khác đang chạy ứng dụng của bạn.
  2. Đặt danh sách thả xuống Throttling (Giới hạn) về trạng thái Online (Trực tuyến).
  3. Nhấn nút Quay lại của Chrome để quay lại trang tìm kiếm.
  4. Nhấn và giữ nút Reload (Tải lại) của Chrome rồi chọn Empty cache and key nạp (Làm trống bộ nhớ đệm và tải lại cứng) để đảm bảo trình chạy dịch vụ của bạn được cập nhật.
  5. Đặt lại danh sách thả xuống Điều tiết thành Ngoại tuyến.
  6. Nhập cụm từ tìm kiếm rồi nhấp lại vào nút Tìm kiếm.
  7. Nhấp vào đăng ký nhận thông báo.
  8. Khi Chrome hỏi bạn có muốn cấp cho ứng dụng quyền gửi thông báo hay không, hãy nhấp vào Allow (Cho phép).
  9. Nhập một cụm từ tìm kiếm khác rồi nhấp lại vào nút Tìm kiếm.
  10. Đặt lại danh sách thả xuống Throttling (Giới hạn) về Online (Trực tuyến).

Sau khi kết nối trở lại, một thông báo sẽ xuất hiện:

Ảnh chụp màn hình toàn bộ quy trình ngoại tuyến.

Kết luận

Workbox cung cấp nhiều tính năng tích hợp sẵn để giúp PWA của bạn linh hoạt và hấp dẫn hơn. Trong lớp học lập trình này, bạn đã tìm hiểu cách triển khai API Đồng bộ hoá dưới nền thông qua bản tóm tắt của Workbox, nhằm đảm bảo các truy vấn ngoại tuyến của người dùng không bị mất và có thể thử lại sau khi kết nối trở lại. Bản minh hoạ là một ứng dụng tìm kiếm đơn giản, nhưng bạn có thể sử dụng cách triển khai tương tự cho các trường hợp và trường hợp sử dụng phức tạp hơn, bao gồm cả ứng dụng trò chuyện, đăng tin trên mạng xã hội, v.v.