Trải nghiệm chỉ đường tức thì

Bổ sung các kỹ thuật tải trước truyền thống bằng trình chạy dịch vụ.

Demián Renzulli
Demián Renzulli
Gilberto Cocchi
Gilberto Cocchi

Việc thực hiện một nhiệm vụ trên trang web thường bao gồm một số bước. Ví dụ: để mua một sản phẩm trên trang web thương mại điện tử, bạn có thể phải tìm kiếm sản phẩm, chọn một mặt hàng trong danh sách kết quả, thêm mặt hàng đó vào giỏ hàng rồi hoàn tất thao tác bằng cách thanh toán.

Về mặt kỹ thuật, việc di chuyển qua các trang khác nhau có nghĩa là tạo một yêu cầu điều hướng. Theo nguyên tắc chung, bạn không nên sử dụng các tiêu đề Cache-Control tồn tại lâu dài để lưu phản hồi HTML vào bộ nhớ đệm cho một yêu cầu điều hướng. Thông thường, các yêu cầu này sẽ được đáp ứng qua mạng bằng Cache-Control: no-cache để đảm bảo rằng HTML, cùng với chuỗi yêu cầu mạng tiếp theo, là mới (ở mức hợp lý). Việc phải chống lại mạng mỗi khi người dùng chuyển đến một trang mới có nghĩa là mỗi thao tác điều hướng có thể bị chậm. Ít nhất, điều này có nghĩa là thao tác điều hướng sẽ không đáng tin cậy và nhanh.

Để tăng tốc các yêu cầu này, nếu có thể dự đoán hành động của người dùng, bạn có thể yêu cầu các trang và thành phần này trước và lưu các trang và thành phần đó vào bộ nhớ đệm trong một khoảng thời gian ngắn cho đến khi người dùng nhấp vào các đường liên kết này. Kỹ thuật này được gọi là tìm nạp trước và thường được triển khai bằng cách thêm thẻ <link rel="prefetch"> vào các trang, cho biết tài nguyên cần tìm nạp trước.

Trong hướng dẫn này, chúng ta sẽ khám phá nhiều cách sử dụng trình chạy dịch vụ để bổ sung cho các kỹ thuật tải trước truyền thống.

Trường hợp sản xuất

MercadoLibre là trang web thương mại điện tử lớn nhất ở Mỹ Latinh. Để tăng tốc độ điều hướng, họ sẽ tự động chèn các thẻ <link rel="prefetch"> vào một số phần của quy trình. Ví dụ: trong các trang danh sách, chúng tìm nạp trang kết quả tiếp theo ngay khi người dùng cuộn xuống cuối trang thông tin:

Ảnh chụp màn hình trang thông tin thứ nhất và thứ hai của MercadoLibre và thẻ Tìm nạp trước đường liên kết kết nối cả hai trang.

Các tệp được tìm nạp trước được yêu cầu ở mức độ ưu tiên "Thấp nhất" và được lưu trữ trong bộ nhớ đệm HTTP hoặc bộ nhớ đệm (tuỳ thuộc vào việc tài nguyên có thể lưu vào bộ nhớ đệm hay không), trong một khoảng thời gian khác nhau tuỳ theo trình duyệt. Ví dụ: kể từ Chrome 85, giá trị này là 5 phút. Tài nguyên được giữ lại trong 5 phút, sau đó các quy tắc Cache-Control thông thường cho tài nguyên sẽ được áp dụng.

Việc sử dụng tính năng lưu vào bộ nhớ đệm của worker dịch vụ có thể giúp bạn kéo dài thời gian hoạt động của các tài nguyên tải trước ngoài khoảng thời gian 5 phút.

Ví dụ: cổng thông tin thể thao Virgilio Sport của Ý sử dụng worker dịch vụ để tải trước các bài đăng phổ biến nhất trên trang chủ. Các ứng dụng này cũng sử dụng API Thông tin mạng để tránh tải trước cho những người dùng đang dùng kết nối 2G.

Biểu trưng của Virgilio Sport.

Do đó, sau hơn 3 tuần quan sát, Virgilio Sport đã chứng kiến thời gian tải để điều hướng đến các bài viết cải thiện 78% và số lượt hiển thị bài viết tăng 45%.

Ảnh chụp màn hình trang chủ và trang bài viết của Virgilio Sport, với các chỉ số tác động sau khi tải trước.

Triển khai tính năng lưu vào bộ nhớ đệm trước bằng Workbox

Trong phần sau, chúng ta sẽ dùng Hộp làm việc để chỉ ra cách triển khai các kỹ thuật lưu bộ nhớ đệm khác nhau trong Service worker có thể dùng làm công cụ bổ sung cho <link rel="prefetch"> hoặc thậm chí là một công cụ thay thế bằng cách uỷ quyền hoàn toàn nhiệm vụ này cho service worker.

1. Lưu trước các trang tĩnh và tài nguyên phụ của trang

Lưu trước là khả năng của worker dịch vụ lưu tệp vào bộ nhớ đệm trong khi cài đặt.

Trong các trường hợp sau đây, quá trình lưu trước vào bộ nhớ đệm được dùng để đạt được mục tiêu tương tự như tìm nạp trước: giúp quá trình điều hướng nhanh hơn.

Lưu các trang tĩnh vào bộ nhớ đệm trước

Đối với các trang được tạo trong thời gian xây dựng (ví dụ: about.html, contact.html) hoặc trong các trang web hoàn toàn tĩnh, người dùng chỉ cần thêm các tài liệu của trang web vào danh sách bộ nhớ đệm trước để các tài liệu này đã có sẵn trong bộ nhớ đệm mỗi khi người dùng truy cập vào các tài liệu đó:

workbox.precaching.precacheAndRoute([
  {url: '/about.html', revision: 'abcd1234'},
  // ... other entries ...
]);

Tài nguyên phụ của trang lưu trữ dữ liệu

Việc lưu các thành phần tĩnh mà các phần khác nhau của trang web có thể sử dụng (ví dụ: JavaScript, CSS, v.v.) vào bộ nhớ đệm trước là một phương pháp hay nhất chung và có thể tăng hiệu suất trong các trường hợp tải trước.

Để tăng tốc độ điều hướng trong trang web thương mại điện tử, bạn có thể sử dụng thẻ <link rel="prefetch"> trong trang thông tin để tải trước trang chi tiết sản phẩm cho một số sản phẩm đầu tiên trên trang thông tin. Nếu bạn đã lưu trước các tài nguyên phụ của trang sản phẩm vào bộ nhớ đệm, thì thao tác này có thể giúp bạn điều hướng nhanh hơn nữa.

Cách triển khai:

  • Thêm thẻ <link rel="prefetch"> vào trang:
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • Thêm tài nguyên phụ của trang vào danh sách lưu vào bộ nhớ đệm trước trong worker dịch vụ:
workbox.precaching.precacheAndRoute([
  '/styles/product-page.ac29.css',
  // ... other entries ...
]);

2. Kéo dài thời gian tồn tại của tài nguyên tìm nạp trước

Như đã đề cập trước đó, <link rel="prefetch"> tìm nạp và lưu giữ tài nguyên trong bộ nhớ đệm HTTP trong một khoảng thời gian giới hạn, sau đó áp dụng các quy tắc Cache-Control cho tài nguyên. Kể từ Chrome 85, giá trị này là 5 phút.

Worker dịch vụ cho phép bạn kéo dài thời gian hoạt động của các trang tải trước, đồng thời mang lại lợi ích bổ sung là cung cấp các tài nguyên đó để sử dụng khi không có mạng.

Trong ví dụ trước, bạn có thể bổ sung cho <link rel="prefetch"> dùng để tìm nạp trước trang sản phẩm bằng Chiến lược lưu vào bộ nhớ đệm trong thời gian chạy Hộp công việc.

Để triển khai việc đó:

  • Thêm thẻ <link rel="prefetch"> vào trang:
 <link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
  • Triển khai chiến lược lưu vào bộ nhớ đệm trong thời gian chạy trong worker dịch vụ cho các loại yêu cầu sau:
new workbox.strategies.StaleWhileRevalidate({
  cacheName: 'document-cache',
  plugins: [
    new workbox.expiration.Plugin({
      maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
    }),
  ],
});

Trong trường hợp này, chúng tôi đã chọn sử dụng chiến lược đã lỗi thời trong khi xác thực lại. Trong chiến lược này, các trang có thể được yêu cầu song song từ cả bộ nhớ đệm và mạng. Phản hồi đến từ bộ nhớ đệm nếu có, nếu không thì đến từ mạng. Bộ nhớ đệm luôn được cập nhật bằng phản hồi mạng với mỗi yêu cầu thành công.

3. Uỷ quyền tải trước cho worker dịch vụ

Trong hầu hết các trường hợp, phương pháp tốt nhất là sử dụng <link rel="prefetch">. Thẻ này là một gợi ý về tài nguyên được thiết kế để giúp việc tìm nạp trước hiệu quả nhất có thể.

Tuy nhiên, trong một số trường hợp, bạn nên uỷ quyền hoàn toàn nhiệm vụ này cho worker dịch vụ. Ví dụ: để tải trước một số sản phẩm đầu tiên trong trang thông tin sản phẩm do phía máy khách hiển thị, bạn có thể cần chèn một số thẻ <link rel="prefetch"> một cách linh động vào trang, dựa trên phản hồi API. Điều này có thể tạm thời làm mất thời gian trên luồng chính của trang và khiến việc triển khai trở nên khó khăn hơn.

Trong những trường hợp như vậy, hãy sử dụng "chiến lược giao tiếp giữa trang và worker" để uỷ quyền hoàn toàn tác vụ tìm nạp trước cho worker. Bạn có thể thực hiện loại giao tiếp này bằng cách sử dụng worker.postMessage():

Biểu tượng của một trang giao tiếp hai chiều với trình chạy dịch vụ.

Gói Workbox Window đơn giản hoá loại giao tiếp này, tóm tắt nhiều thông tin chi tiết về lệnh gọi cơ bản đang được thực hiện.

Bạn có thể triển khai tính năng tìm nạp trước bằng Cửa sổ Workbox theo cách sau:

  • Trong trang: gọi trình chạy dịch vụ, truyền cho trình chạy dịch vụ loại thông báo và danh sách URL để tải trước:
const wb = new Workbox('/sw.js');
wb.register();

const prefetchResponse = await wb.messageSW({type: 'PREFETCH_URLS', urls: []});
  • Trong trình chạy dịch vụ: triển khai trình xử lý thông báo để đưa ra yêu cầu fetch() cho mỗi URL để tải trước:
addEventListener('message', (event) => {
  if (event.data.type === 'PREFETCH_URLS') {
    // Fetch URLs and store them in the cache
  }
});