Lớp học lập trình này hướng dẫn bạn 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 Remix to Edit (Trộn 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 Toàn màn hình .
Trong thẻ mới vừa mở, hãy kiểm tra cách hoạt động của trang web khi ở chế độ ngoại tuyến:
- Nhấn tổ hợp phím `Ctrl+Shift+J` (hoặc `Command+Option+J` trên máy Mac) để mở DevTools.
- Nhấp vào thẻ Mạng.
- 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.
- Trong danh sách thả xuống về Throttling (Giới hạn), hãy chọn Offline (Khi không có mạng).
- 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:
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 lưu vào bộ nhớ đệm trước tại thời điểm tạo bản 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 đã 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:
- Để xem nguồn, hãy nhấn vào Xem nguồn.
- 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:
- Quay lại thẻ khác đang chạy ứng dụng của bạn.
- Đặt danh sách thả xuống Throttling (Giới hạn) về trạng thái Online (Trực tuyến).
- Nhấn nút Quay lại của Chrome để quay lại trang tìm kiếm.
- Đảm bảo bạn đã tắt hộp đánh dấu Disable cache (Tắt bộ nhớ đệm) trong DevTools.
- Nhấn và giữ nút Tải lại của Chrome rồi chọn Rỗng bộ nhớ đệm và tải lại hoàn toàn để đảm bảo rằng worker dịch vụ của bạn được cập nhật.
- Đặt lại danh sách thả xuống Throttling (Giới hạn) về Offline (Ngoại tuyến).
- 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:
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 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, hàm này sẽ gọiNotification.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ặcdefault
. - 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.
- Mở
public/sw.js
để chỉnh sửa. - 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}¬ification=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 để các yêu cầu đã xếp hàng được truy xuất 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
, nối thêm tham số truy vấn¬ification=true
để có thể nhận được 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],
}),
);
Điều này yêu cầu Workbox luôn truy cập vào mạng và khi các 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
- Quay lại thẻ khác đang chạy ứng dụng của bạn.
- Đặt danh sách thả xuống Throttling (Giới hạn) về trạng thái Online (Trực tuyến).
- Nhấn nút Quay lại của Chrome để quay lại trang tìm kiếm.
- Nhấn và giữ nút Tải lại của Chrome rồi chọn Rỗng bộ nhớ đệm và tải lại hoàn toàn để đảm bảo rằng worker dịch vụ của bạn được cập nhật.
- Đặt lại danh sách thả xuống Throttling (Giới hạn) về Offline (Ngoại tuyến).
- Nhập cụm từ tìm kiếm rồi nhấp lại vào nút Tìm kiếm.
- Nhấp vào đăng ký nhận thông báo.
- 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 Cho phép.
- 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.
- Đặ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:
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á ở chế độ nền thông qua Workbox trừu tượng, để đảm bảo rằng các truy vấn của người dùng khi không có kết nối mạng sẽ không bị mất và có thể thử lại sau khi kết nối được khôi phục. 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 phương thức 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.