Preload, Prefetch, Preconnect là gì? Sao chúng có thể cải tiến hiệu năng web performance 1 cách đáng kể?

Bài Học

Vào thời điểm hiện tại, các trình duyệt browser hiện đại như Chrome, Safari, hay cả như Edge đã tích hợp sẵn các công nghệ giúp cải thiện hiệu năng web performance lên 1 cách đáng kể, giúp nâng cao trải nghiệm người dùng trên website của bạn ngay ở phía client side.

Khi nhắc đến việc cải tiến hiệu năng web performance, bạn thường nghĩ ngay tới các kỹ thuật caching phức tạp, sẽ phải thực hiện tối ưu ở phía server side, phải chỉnh sửa nhiều đoạn source code ở nhiều lớp layer, hay nhiều module khác nhau, để lồng ghép xử lý caching rối rắm vào đó. Đôi khi giải pháp tối ưu thật sự lại rất đơn giản, khi bạn biết về nó thì hóa ra lại không có gì to tát hay phức tạp cả, đặc biệt là các tối ưu hóa ở phía client side: bạn chỉ cần render thêm 1 vài thẻ tags hay thẻ metadata ở lớp view layer là đủ để browser hiểu và tự động tối ưu hóa hiệu năng cho web của bạn.

preload, prefetch, preconnect thực chất là các chỉ thị thông báo cho browser các chỉ dẫn xử lý, biểu hiện 1 thẻ <link/> có rel=”preload” (hoặc prefetch, preconnect) mà ta sẽ render thêm ở view layer hoặc thông qua HTTP headers, mục đích của chúng dùng để thông báo cho browser biết cách tối ưu việc tìm nạp các tài nguyên resources (images, js, css, font, …) từ server, dùng giảm thời gian xử lý network khứ hồi round trips, tận dụng thời gian người dùng đang đọc thông tin trên trang page để tìm nạp trước các nguồn tài nguyên resources của website.

Preload

Preload(tải trước theo trình tự ưu tiên) là chỉ thị cho bạn nhiều quyền kiểm soát hơn về trình tự ưu tiên tìm nạp tài nguyên resources cụ thể trong trình duyệt browser, đối với điều hướng hiện tại. Chỉ dẫn preload được định nghĩa trong 1 thẻ <link rel=”preload”>. Thông thường chỉ dẫn này dùng để nạp trước các tài nguyên có độ ưu tiên quan trọng như images, CSS, JS và font files, muốn được nạp sẵn trước khi browser thực hiện rendering. Do đó đảm bảo các nguồn tài nguyên resources luôn được nạp sẵn, và hầu như không block quá trình render của trang page, do đó sẽ cải thiện hiệu năng tải trang page.

Lưu ý preload khác biệt hoàn toàn với prefetch (tìm nạp tải trước), vì nó tập trung vào điều hướng hiện tại của người dùng, dùng để nạp trước các tài nguyên resources được thiết lập có độ ưu tiên cao, còn prefetch tập trung vào tìm nạp trước tài nguyên resources cho điều hướng tiếp theo mà người dùng có khả năng truy cập tới(các nguồn tài nguyên này có độ ưu tiên thấp hơn). Điểm đặc biệt cần chú ý tại đây là preload không block sự kiện onload event.

Lợi ích của preload

Các lợi ích của chỉ thị preload như sau:

  • Cho phép trình duyệt browser thiết lập độ ưu tiên nạp tài nguyên resource.
  • Cho phép trình duyệt browser khả năng xác định được loại tài nguyên resource type do đó nó có thể cho biết liệu cùng một tài nguyên có thể được tái sử dụng trong tương lai hay không.
  • Trình duyệt browser có thể xác định xem yêu cầu request có tuân thủ chính sách bảo mật nội dung content security policy hay không bằng cách tham chiếu những gì được xác định trong thuộc tính as.
  • Trình duyệt browser có thể gửi kèm theo các accept headers thích hợp dựa vào loại tài nguyên resource type (ví dụ như image/webp)

Cách sử dụng preload

Dưới đây là ví dụ về cách nạp trước preloading 1 image.

<link rel="preload" href="image.png">

Tiếp là ví dụ về nạp trước preloading fonts. Chú ý: nếu bạn nạp trước các links với tài nguyên resources ở domain khác thì bạn cần thêm vào thuộc tính crossorigin.

<link rel="preload" href="https://example.com/fonts/font.woff" as="font" crossorigin>

Tiếp là ví dụ về preloading 1 stylesheet bằng cách sử dụng thẻ hay được tạo động bởi JS.

<!-- Via markup --><link rel="preload" href="/css/mystyles.css" as="style"><!-- Via JavaScript --><script>var res = document.createElement("link");res.rel = "preload";res.as = "style";res.href = "css/mystyles.css";document.head.appendChild(res);</script>

Bạn có thể sử dụng thuộc tính as để chỉ thị cho trình duyệt browser loại type của content cần ưu tiên nạp trước :

  • Thiết lập trình tự ưu tiên nạp resource chính xác hơn.
  • Có gắng tái sử dụng lại cùng 1 resource đối với các requests ở tương lai nếu có thể.
  • Cho phép áp dụng chính sách bảo mật nội dung content security policyđối với resource.
  • Thiết lập đúng Accept request headers khi thực hiện yêu cầu nạp resource.

Có rất nhiều loại content types có thể được preloaded, cũng như có nhiều loại các giá trị của thuộc tính as như sau:

  • audio: Audio file.
  • document : 1 HTML document được nhúng bên trong <frame> hay <iframe>.
  • embed : 1 resource được nhúng bên trong <embed>.
  • fetch : loại resource có thể được nạp bởi fetch hay XHR request giống như ArrayBuffer hay JSON file.
  • font : Font file.
  • image : Image file.
  • object : 1 resource được nhúng bên trong <embed>.
  • script : JavaScript file.
  • style : Stylesheet.
  • track : WebVTT file.
  • worker : 1 JavaScript web worker hay shared worker.
  • video : Video file.

Khả năng hỗ trợ chỉ thị preload của các trình duyệt browser

Preload được hỗ trợ từ phiên bản Chrome 50 bắt đầu từ tháng 4 năm 2016(https://www.chromestatus.com/feature/5757468554559488) và cũng được hỗ trợ từ Opera 37+(http://caniuse.com/#search=preload). Và nó vẫn chưa được xác nhận sẽ được hỗ trợ trong Mozilla Firefox và Microsoft Edge.

Mức độ hỗ trợ preload của các trình duyệt browser.

Để tìm hiểu thêm và rõ ràng hơn về chỉ thị preload, bạn có thể đọc tại đây: https://www.keycdn.com/support/preload-directive

Prefetch

Prefetch là cơ chế cho phép trình duyệt browser tìm nạp ngầm trước các tài nguyên resources(các tài nguyên này được đánh giá ở mức độ ưu tiên thấp khi trình duyệt thực hiện tìm nạp) mà có thể cần tới ở tương lai, và lưu trữ chúng trong cache của browser. Khi 1 page được thực nạp xong, thì browser bắt đầu tìm nạp trước các nguồn tài nguyên resources có thể sẽ được người dùng truy cập tới trong tương lai. Nếu người dùng ấn vào 1 link đã được nạp trước, thì ngay lập tức nội dung page tương ứng với link đó sẽ nạp sẵn. Có 3 loại prefetching: link, DNS và prerendering(ta sẽ đề cập chi tiết hơn ở dưới).

1. Link Prefetching

link prefetching cho phép trình duyệt browser tìm nạp trước tài nguyên resources, và lưu trữ chúng trong cache. Trình duyệt browser sẽ tìm nạp các links nằm trong HTML hoặc trong HTTP header như sau:

  • HTML: <link rel=”prefetch” href=”/uploads/images/pic.png”>
  • HTTP Header: Link: </uploads/images/pic.png>; rel=prefetch

“Kỹ thuật này có tiềm năng tăng tốc nhiều trang web có độ tương tác cao, nhưng sẽ không phải luôn mang lại hiệu quả với mọi trang web. Đối với 1 vài trang web, rất khó để xác định được người dùng có thể truy cập tới trang page nào tiếp theo. Đối với 1 vài trang web khác, dữ liệu có thể sẽ trở nên chẳng thú vị gì nếu được nạp sẵn trước đó. Bạn cũng nên cẩn thận để không tìm nạp trước các files quá sớm hoặc bạn có thể làm chậm trang mà người dùng đã xem. — Google Developers”

Link prefetch được hỗ trợ bởi hầu hết các trình duyệt browsers, ngoại trừ Safari, IOS Safari, và Opera Mini. Chrome và Firefox cũng chỉ rõ các tài nguyên nào được nạp trước(prefetched resources) trong network panel nếu bạn muốn test.

Mức độ hỗ trợ link prefetch của các trình duyệt browser.

2. DNS Prefetching

Cơ chếDNS prefetching cho phép browser thực hiện tìm nạp ngầm DNS ngay trên page trong khi người dùng đang duyệt trang. Điều này làm tối thiểu hóa độ trễ tìm nạp DNS, DNS luôn có sẵn khi người dùng ấn vào 1 link.

“Yêu cầu DNS requests sử dụng lượng băng thông cực kỳ nhỏ, nhưng độ trễ khi tìm nạp DNS lại tương đối cao, đặc biệt nhất là trên kết nối mobile networks. Bằng cách tìm nạp trước các kết quả DNS, độ trễ có thể giảm đáng kể vào một số trường hợp nhất định, chẳng hạn như khi người dùng nhấp vào liên kết link. Trong một sốtrường hợp, độ trễ có thể giảm tới một giây. — Mozilla Developer Network

Ví dụ về cách sử dụng DNS prefetching:

<!-- Prefetch DNS for external assets --> <link rel="dns-prefetch" href="//fonts.googleapis.com"> <link rel="dns-prefetch" href="//www.google-analytics.com"> <link rel="dns-prefetch" href="//opensource.keycdn.com"> <link rel="dns-prefetch" href="//cdn.domain.com">

1 điều khá thú vị: Google Chrome cũng thực hiện 1 cơ chế tương tự như DNS prefetching khi bạn gõ trong thanh địa chỉ của nó. Bạn có thể kiểm tra điều này khi truy cập vào chrome://dns/

Bạn cũng có thể sử dụng module có sẵn như Pagespeed filter insert_dns_prefetch để tự động tạo ra các thẻ <link rel=”dns-prefetch”> trong header cho mọi domains.

DNS prefetch cũng được hỗ trợ bởi hầu hết bởi các trình duyệt hiện đại ngoại trừ Opera Mini.

Mức độ hỗ trợ dns prefetch của các trình duyệt browser.

3. Prerendering

Prerendering(hiện thị trước) cũng khá tương đồng với prefetching(tìm nạp trước) là sẽ nạp trước toàn bộ tập hợp các resources trong trang page mà người dùng có thể truy cập tới tiếp theo. Điểm khác biệt là prerendering thực chất sẽ nạp ngầm trước toàn bộ trang page, bao gồm các tài nguyên có trong 1 document. Xét ví dụ sau:

<link rel="prerender" href="https://www.keycdn.com">

“Cơ chế hiện thị trước prerender có thể được điều khiển bởi ứng dụng của bạn để xác định xem chuyển hướng tới trang HTML nào tiếp theo được thực hiện: Trình duyệt sẽ nạp và xử lý nguồn tài nguyên được định trước để nạp giống như 1 phản hồi HTML response. Để nạp về các loại nội dung khác với request headers thích hợp hay nếu tài nguyên không phải HTML, thì ứng dụng có thể sử dụng cơ chế prefetch — W3C

Bạn nên lưu ý rằng cơ chế prerendering đi kèm với việc nạp trước tài nguyên resource tương đối lớn, và có thể gây ra sự lãng phí băng thông, đặc biệt là trên các thiết bị mobile. Bạn cũng nên lưu ý là bạn không thể test được nó với công cụ Chrome DevTools, thay vào đó bạn chỉ có thể biết được 1 page có được prerendered trước hay không bằng cách truy cập vào chrome://net-internals/#prerender. Hay bạn cũng có thể test được bằng sử dụng trang prerender-test.appspot.com.

Prerender chỉ được hỗ trợ bởi 1 vài trình duyệt browsers, ngoại trừ Mozilla Firefox, Safari, IOS Safari, Opera Mini, và Edge.

Mức độ hỗ trợ prerender của các trình duyệt browser.

Có 1 vài nhược điểm khi sử dụng cơ chế này, ví dụ như các chỉ trích liên quan tới quyền riêng tư.

  • Thống kê truy cập web có thể bị thổi phồng so với thực tế.
  • Người dùng có thể gặp nhiều rủi ro về bảo mật hơn khi phải thục hiện tải về nhiều pages hơn, hay tải các resource đến từ các sites không mong muốn truy cập tới.
  • Người dùng có thể vi pháp chính sách sử dụng của chính network hay tổ chức của họ nếu tìm nạp trước các nội dung không được cấp phép.

Để hiểu hơn bạn đoc tại đây: prefetching.

Preconnect

Preconnect(khởi tạo kết nối trước) cho phép trình duyệt browser thiết lập các kết nối connections sớm trước cả khi 1 HTTP request thực sự được gửi tới server. Các kêt nối loại này bao gồm: DNS lookups, TLS negotiations, TCP handshakes. Kỹ thuật này giảm thiểu độ trễ khứ hồi roundtrip và tiết kiệm thời gian cho người dùng.

“Preconnect là 1 công cụ quan trọng trong bộ công cụ tối ưu của bạn …Nó có thể giảm thiểu chi phí khứ hồi roundtrips của request — trong 1 vài trường hợp, nó có thể giảm độ trễ của request xuống hàng trăm hay thậm chí hàng nghìn milliseconds — Ilya Grigorik

1 preconnect có thể được thêm vào 1 cách trực tiếp trong 1 thuộc tính của thẻ link trong HTML. Nó cũng có thể được thiết lập thông qua HTTP header hoặc có thể được tạo động bởi JS. Dưới là ví dụ bật preconnect cho 1 CDN URL.

<link href="https://cdn.domain.com" rel="preconnect" crossorigin>

Phía dưới là ví dụ về việc sử dụng preconnect với Google Fonts. Bằng việc thêm vào chỉ dẫn preconnect cho fonts.gstatic.com, nó khiến việc khởi tạo request nạp font diễn ra song song với CSS request, cho phép font request được gửi đi dường như ngay lập tức. Muốn xem chi tiết hơn thì bạn truy cập vào eliminating RTTS with preconnect.

Tại trường hợp không sử dụng preconnect, browser sau khi nạp toàn bộ HTML rồi mới biết nó cần thêm tài nguyên CSS resource nằm trong fonts.googleapis.com. Sau khi tải xong tài nguyên CSS này, browser lại mới biết trang page cần 2 fonts nữa, và nó bắt đầu khởi tạo để nạp 2 fonts này từ fonts.gstatic.com – trước hết, browser vẫn cần thực hiện lại các bước DNS, TCP, và TLS handshakes ngay cả khi kết nối socket đã có sẵn cho các requests đa kênh trên kết nối HTTP/2. 

<link href='https://fonts.gstatic.com' rel='preconnect' crossorigin>
<link href='https://fonts.googleapis.com/css?family=Roboto+Slab:700|Open+Sans' rel='stylesheet'>

Với trường hợp, khi ta thêm vào chỉ thị preconnect để chỉ dẫn cho browser, trang page sẽ cần nạp tài nguyên resources từ  fonts.gstatic.com. Như kết quả ở trên, browser đã thiết lập kết nối socket song song với yêu cầu CSS request, và hoàng thành yêu cầu nạp tài nguyên trước hạn, cho phép font requests được gửi đi gần như lập tức.

Preconnect được hỗ trợ bởi 1 vài trình duyệt, ngoại trừ Internet Explorer, và Opera Mini.

Mức độ hỗ trợ preconnect của các trình duyệt browser.

Để hiểu hơn bạn đoc tại đây: preconnect.



Comments

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *