Categories Tải trước

Prefetch là gì? Tìm nạp trước tài nguyên để tăng tốc các truy cập kế tiếp của người dùng

Trong bài viết này chúng ta sẽ cùng tìm hiểu về thẻ rel=prefetch dùng trong việc gợi ý tài nguyên (resource hints) và cách sử dụng nó.

Nghiên cứu chỉ ra rằng tốc độ tải trang nhanh hơn đem đến hệ quả có lợi là tỷ lệ chuyển đổi cao hơn và tất nhiên: các trải nghiệm người dùng tốt hơn. Nếu bạn nhìn sâu vào chuỗi truy cập của người dùng trên website và biết được các trang họ có khả năng sẽ truy cập tiếp, bạn có thể cải thiện thời gian tải trang của truy cập trong tương lai (future navigations) bằng cách tải các tài nguyên cho những trang đó trước khi họ thực sự click vào liên kết (ahead of time).

Hướng dẫn này giải thích cách thực hiện điều đó với thẻ <link rel=prefetch>, một công cụ gợi ý tài nguyên cho phép bạn triển khai tìm nạp trước (prefetching) một cách dễ dàng và hiệu quả.

Cải thiện điều hướng bằng rel=prefetch

Thêm <link rel=prefetch> vào trang web nói cho trình duyệt là nó hãy tải toàn bộ các trang, hoặc một số tài nguyên (chẳng hạn như file JS hoặc CSS), mà người dùng có thể cần dùng đến trong tương lai. Điều này có thể cải thiện các chỉ số như First Contentful Paint (thời gian người dùng nhìn thấy phản hồi bằng hình ảnh đầu tiên từ trang) và Time To Interactive (thời gian người dùng có khả năng tương tác với website) và có thể giúp các truy cập kế tiếp (subsequent navigations) hiển thị gần như ngay lập tức.

Cấu trúc:

<link rel="prefetch" href="index.html" as="document">
cách prefetch làm việc
Cách prefetch làm việc

Cần lưu ý là gợi ý prefetch tiêu thụ tài nguyên bổ sung mà không cần thiết ngay ở thời điểm hiện tại, vì thế kỹ thuật này cần được áp dụng một cách cẩn trọng; chỉ prefetch các tài nguyên khi bạn tự tin rằng người dùng sẽ cần đến chúng trong tương lai gần. Hãy cẩn trọng tránh prefetch khi người dùng đang trên mạng có kết nối chậm. Bạn có thể phát hiện điều đó bằng API Network Information.

Có nhiều cách xác định nên tìm nạp trước các liên kết nào. Cách đơn giản nhất là prefetch liên kết đầu tiên hoặc vài liên kết đầu tiên trên trang hiện tại. Cũng có một số thư viện giải quyết điều này thông qua các cách tiếp cận tinh vi hơn, các giải thích cụ thể sẽ được tôi nói ở các phần tiếp theo của bài viết này.

Các trường hợp áp dụng

Prefetch các trang kế tiếp

Prefetch các tài liệu HTML khi các trang kế tiếp nằm trong khả năng dự đoán, vì thế khi người dùng click vào link, trang được tải gần như ngay lập tức (loaded instanly).

Lấy ví dụ, trong một trang danh sách sản phẩm, bạn có thể prefetch các trang sản phẩm phổ biến nhất trong danh sách. Trong một số trường hợp, điều hướng kế tiếp rất dễ dự đoán-ví dụ trên trang giỏ hàng, khả năng người dùng truy cập trang thanh toán thường cao, và nó rõ ràng là ứng cử viên tốt để prefetch.

eBay triển khai prefetch cho năm kết quả đầu tiên trên trang tìm kiếm để tăng tốc thời gian tải trang có thể được truy cập trong tương lai và họ thấy thay đổi này ảnh hưởng tích cực đến tỷ lệ chuyển đổi.

Tìm nạp trước các tài nguyên tĩnh

Prefetch các tài nguyên tĩnh, chẳng hạn như JS hoặc CSS, khi các phần tiếp theo mà người dùng có thể truy cập có khả năng được dự đoán. Điều này đặc biệt có ích khi những tài nguyên này được chia sẻ trên nhiều trang.

Lấy ví dụ, Netflix tận dụng thời gian người dùng thực hiện khi đăng xuất trang để prefetch React, cái sẽ được dùng khi người dùng đăng nhập trở lại. Nhờ điều này mà họ giảm được 30% thời gian tương tác cho các điều hướng tương lai.

Tại thời điểm viết bài này, đã có khả năng chia sẻ các tài nguyên prefetch giữa các trang được phục vụ từ các host gốc khác nhau. Khi khóa kép HTTP cache được chuyển (?), điều này sẽ chỉ hoạt động cho các điều hướng cấp cao nhất (top-level) và nguồn phụ cùng gốc (subresource), nhưng nó sẽ không có khả năng tái sử dụng các nguồn phụ đã được prefetch giữa các host gốc khác nhau. Điều này có nghĩa là, nếu a.com prefetch nguồn b.com/library.js, nó không thể được sử dụng cho cache của tên miền c.com. Một số trình duyệt, chẳng hạn như các trình duyệt dựa trên WebKit, đã lưu trữ bộ nhớ cache và lưu trữ HTML5 cho tất cả tên miền của bên thứ ba.

Tìm nạp trước các đoạn mã JavaScript theo yêu cầu

Code-splitting (phân chia / tách mã) JavaScript của trang cho phép bạn chỉ tải ban đầu một phần và lazy-load (tải lười) phần còn lại. Nếu bạn sử dụng kỹ thuật này, bạn có thể áp dụng prefetch cho thành phần không cần thiết ngay lập tức nhưng sẽ có khả năng được yêu cầu sớm.

Lấy ví dụ, nếu bạn có một trang bao gồm một nút bấm mở ra một hộp thoại có chứa các lựa chọn emoji (biểu tượng mặc cười, mặt mếu, vân vân), bạn có thể chia nó làm ba đoạn mã JavaScript, bao gồm: home, dialog (hộp thoại) và picker (lựa chọn). Home và dialog có thể được tải lúc ban đầu (initially loaded), trong khi picker có thể được tải theo kiểu ‘theo yêu cầu’ (on-demand), vì nó không phải là thành phần chắc chắn được sử dụng ngay lập tức. Các công cụ như webpack cho phép bạn hướng dẫn trình duyệt để nó prefetch những đoạn mã ‘theo yêu cầu’.

Cách triển khai rel=prefetch

Cách thức dễ dàng nhất để triển khai prefetch là thêm thẻ <link> vào phần <head> của tài liệu:

<head>
	...
	<link rel="prefetch" href="index.html" as="document">
	...
</head>

Thuộc tính as là không bắt buộc phải có, nhưng được khuyên là nên dùng. Nó giúp trình duyệt thiết lập các header chính xác, và xác định xem liệu tài nguyên đã có trong cache hay chưa. Ví dụ các giá trị cho thuộc tính này có thể bao gồm: document, script, style, font, image, vân vân.

Bạn cũng có thể thực hiện prefetch thông qua link HTTP header:

Link: </css/style.css>; rel=prefetch

Lợi ích của việc chỉ định gợi ý prefetch trong HTTP header là trình duyệt không cần phân tích tài liệu để tìm gợi ý tài nguyên, điều này có nghĩa là nó sẽ giúp tốc độ website được cải thiện hơn nữa trong một số trường hợp, mặc dù mức độ cải thiện không nhiều.

Prefetch được hỗ trợ trên tất cả các trình duyệt hiện đại ngoại trừ Safari. Bạn có thể triển khai kỹ thuật dự phòng (fallback) cho Safari bằng các yêu cầu XHR hoặc Fetch API.

Prefetch các module JavaScript với Webpack Magic Comments

Webpack cho phép bạn prefetch các đoạn mã cho các tuyến hoặc chức năng mà có một lượng người dùng hợp lý nhất định sẽ truy cập hoặc sử dụng sớm.

Đoạn mã sau lazy-loads một hàm sắp xếp từ thư viện lodash để sắp xếp một nhóm số sẽ được submit từ một form:

Thay vì chờ đợi sự kiện ‘submit/gửi’ diễn ra rồi mới tải chức năng này, bạn có thể prefetch nguồn này để tăng cơ hội nó có mặt trong cache vào thời điểm người dùng thực sự submit form (qua đó tăng tốc độ xử lý). Webpack cho phép sử dụng magic comments bên trong import():

form.addEventListener("submit", e => {
   e.preventDefault()
   import(/* webpackPrefetch: true */ 'lodash.sortby')
         .then(module => module.default)
         .then(sortInput())
         .catch(err => { alert(err) });
});

Điều này nói với webpack để nó bơm thẻ <link rel=”prefetch”> vào trong tài liệu HTML:

<link rel="prefetch" as="script" href="1.bundle.js">

Prefetch thông minh hơn với quicklink và Guess.js

Bạn có thể triển khai kỹ thuật prefetch thông minh hơn với các thư viện sử dụng prefetch kiểu ‘under the hood’:

  • Quicklink sử dụng Intersection Observer API để nhận biết các liên kết trong viewport (khung nhìn trình duyệt) và prefetch các link tài nguyên trong thời gian rảnh rỗi (idle time). Điểm cộng: qucklink chỉ nặng chưa đến 1 KB!
  • Guess.js sử dụng báo cáo phân tích của công cụ kiểu như Google Analytics để xây dựng lên một mô hình dự đoán nhằm prefetch thông minh hơn chỉ các liên kết mà người dùng có khả năng cao sẽ cần đến.

Cả quicklink và Guess.js đều sử dụng API Network Information để tránh prefetch nếu người dùng đang sử dụng mạng chậm chạp hoặc Save-Data đang được bật.

Công ty đồ uống Jabong triển khai prefetch với quicklink và đạt được tốc độ tải trang xét trên khía cạnh tương tác (Time To Interactive) nhanh hơn 2,7s trên các trang được truy cập trong tương lai.

Prefetch kiểu ‘under the hood’

Các gợi ý tài nguyên không phải là hướng dẫn bắt buộc và nó phụ thuộc vào trình duyệt quyết định xem nó có được thực thi hay không, và nếu được thì thực thi vào lúc nào (decide if, and when, they get excuted).

Bạn có thể sử dụng prefetch nhiều lần trên cùng một trang. Trình duyệt sắp hàng tất cả các gợi ý và gửi yêu cầu từng tài nguyên khi trong thời gian rảnh rỗi. Trong Chrome, nếu một prefetch không hoàn thành tải và người dùng điều hướng đến chính tài nguyên đang được tìm nạp dang dở đó thì tải in-flight được chọn làm điều hướng bằng trình duyệt (các trình duyệt khác có thể triển khai điều này không giống như vậy).

Prefetch diễn ra ở mức độ ưu tiên thấp nhất (lowest priority), do vậy prefetch tài nguyên không cạnh tranh băng thông với các tài nguyên được yêu cầu trong trang hiện tại (trang mà người dùng đang duyệt).

Prefetch các file được lưu trữ trong HTTP cache, hoặc memory cache (phụ thuộc vào liệu tài nguyên đó đã được cache hay chưa), trong khoảng thời gian còn tùy thuộc vào từng trình duyệt. Lấy ví dụ, các tài nguyên Chrome được giữ trong khoảng năm phút, sau đó thì các quy tắc cache-control thông thường cho tài nguyên sẽ được áp dụng.

Kết luận

Sử dụng prefetch có thể cải thiện rất tốt thời gian tải trang cho điều hướng trong tương lai và thậm chí có thể làm trang hiển thị gần như ngay lập tức. Prefetch được rất nhiều trình duyệt hiện đại hỗ trợ, điều đó làm cho nó trở thành kỹ thuật hấp dẫn để cải thiện trải nghiệm của điều hướng kế tiếp cho nhiều người dùng. Kỹ thuật này yêu cầu tải nhiều dữ liệu hơn mà có thể nó không được sử dụng, vì thế hãy tỉnh táo khi bạn sử dụng nó; chỉ sử dụng prefetch khi cần thiết mà thôi, và lý tưởng nhất là trên các mạng có kết nối nhanh.

(Dịch từ bài viết: Prefetch resources to speed up future navigations, tác giả: Demian Renzulli)

Bonus

Bạn nào đang dùng WordPress và muốn tích hợp tính năng prefetch có thể dùng plugin Flying Pages. Lưu ý là cả RAM và CPU sẽ tăng sử dụng do bạn tải trước các liên kết, mức độ tăng tùy thuộc số lượng liên kết bạn muốn tải trước, nhưng có thể lên đến gấp đôi hoặc gấp ba so với thông thường. Do vậy nó sẽ không phù hợp trên hosting yếu. Nếu bạn dùng cả CDN nữa (với kiểu tính tiền theo dung lượng tải về), nó có khả năng làm bạn tốn thêm chi phí đáng kể.

Ngoài prefetch, bạn nên tìm hiểu thêm các cơ chế ‘pre / gợi ý tài nguyên’ khác như preconnectpreload ở các link tương ứng.

Back to Top