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à mã sử dụng có chứa hộp tìm kiếm gọi đ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 biện pháp 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 Remix để chỉnh sửa (Remix) để chỉnh sửa dự án.
  • Để xem trước trang web, hãy nhấn vào View App (Xem ứng dụng), sau đó nhấn vào Fullscreen toàn màn hình (Toàn màn hình).

Trong thẻ mới vừa mở, hãy kiểm tra xem trang web hoạt động như thế nào khi ngoại tuyến:

  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ẻ 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 Điều tiết lưu, chọn Ngoại tuyến.
  5. Trong ứng dụng minh hoạ, hãy nhập một cụm từ tìm kiếm rồi nhấp vào nút Tìm kiếm.

Trang lỗi trình duyệt chuẩn được hiển thị:

Ảnh chụp màn hình về trải nghiệm người dùng ngoại tuyến mặc định trong 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 bộ nhớ đệm trước để luôn có thể lưu trang này vào bộ nhớ đệm tại sự kiện của trình chạy dịch vụ install.

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 khi xây dựng, bằng cách tích hợp thư viện với công cụ tạo bản dựng mà bạn chọn (ví dụ: webpack hoặc gulp).

Để đơn giản hoá, chúng tôi đã làm cho bạn. Mã sau đây tại public/sw.js sẽ giúp bạn 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ả yêu cầu.
  • Khai báo một 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ề trang HTML ngoại tuyến dự phòng.

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 Điều tiết (Điều tiết) thành Trực tuyến.
  3. Nhấn vào 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 Vô hiệu hoá 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 Hard upload (Xoá 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 Điều tiết thành 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 được hiển thị:

Ảnh chụp màn hình về trải nghiệm người dùng ngoại tuyến tuỳ chỉnh trong trình duyệt.

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

Để đơn giản hoá, 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 một 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 của trình duyệt mặc định. Lời hứa này sẽ được giải quyết 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 cho showOfflineText() để hiện 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 trở lại

Tiếp theo, hãy triển khai tính năng Đồng bộ hoá nền hộp làm việc để duy trì các truy vấn ngoại tuyến để có thể thử lại các truy vấn này khi trình duyệt phát hiện thấy có 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 duy trì trong IndexedDB.
  • maxRetentionTime cho biết khoảng thời gian sẽ thử lại yêu cầu. Trong trường hợp này, chúng tôi đã chọn 60 phút (sau đó sẽ bị loại bỏ).
  • onSync là phần quan trọng nhất trong 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ể tiếp nhận mục 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á dưới nền với dịch vụ của bạn, hãy xác định chiến lược NetworkOnly (Chỉ mạng) cho các yêu cầu đến URL tìm kiếm (/search_action) và chuyển bgSyncPlugin đã được 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 kết nối mạng và khi yêu cầu không thành công, hãy dùng logic đồng bộ hoá trong 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, 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)
  );
});

Thử nghiệm 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 Điều tiết (Điều tiết) thành Trực tuyến.
  3. Nhấn vào 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 Hard upload (Xoá 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 Điều tiết (Điều tiết) thành Trực tuyến.

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

Ảnh chụp màn hình của 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 trở nê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á nền bằng phương pháp trừu tượng hoá Workbox để đảm bảo rằng 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 có 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 tình huống 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 nhắn lên mạng xã hội, v.v.