Lớp học lập trình: Tải trước các thành phần quan trọng để cải thiện tốc độ tải

Trong lớp học lập trình này, hiệu suất của trang web sau đây được cải thiện bằng cách tải trước và tìm nạp trước một số tài nguyên:

Ảnh chụp màn hình ứng dụng

Đo

Trước tiên, hãy đo lường hiệu suất của trang web trước khi thêm bất kỳ tính năng tối ưu hoá nào.

  • Để 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 toàn màn hình.

Chạy quy trình kiểm tra hiệu suất của Lighthouse (Lighthouse > Options > Performance (Lighthouse > Tuỳ chọn > Hiệu suất)) trên phiên bản trực tiếp của Glitch (xem thêm phần Khám phá các cơ hội về hiệu suất bằng Lighthouse).

Lighthouse cho thấy quy trình kiểm tra không thành công sau đây đối với một tài nguyên được tìm nạp trễ:

Lighthouse: Kiểm tra yêu cầu tải trước khoá
  • 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.
Bảng điều khiển mạng có tài nguyên được phát hiện muộn

Tệp main.css không được phần tử Đường liên kết (<link>) đặt trong tài liệu HTML tìm nạp, mà là một tệp JavaScript riêng biệt, fetch-css.js, đính kèm phần tử Đường liên kết vào DOM sau sự kiện window.onLoad. Điều này có nghĩa là tệp chỉ được tìm nạp sau khi trình duyệt hoàn tất việc phân tích cú pháp và thực thi tệp JS. Tương tự, phông chữ web (K2D.woff2) được chỉ định trong main.css chỉ được tìm nạp sau khi tệp CSS tải xong.

Chuỗi yêu cầu quan trọng thể hiện thứ tự các tài nguyên được trình duyệt ưu tiên và tìm nạp. Đối với trang web này, trang web hiện có dạng như sau:

├─┬ / (initial HTML file)
  └── fetch-css.js
    └── main.css
      └── K2D.woff2

Vì tệp CSS nằm ở cấp thứ ba của chuỗi yêu cầu, nên Lighthouse đã xác định tệp này là tài nguyên được phát hiện muộn.

Tải trước các tài nguyên quan trọng

Tệp main.css là một thành phần quan trọng cần thiết ngay khi trang được tải. Đối với các tệp quan trọng như tài nguyên này được tìm nạp muộn trong ứng dụng, hãy sử dụng thẻ tải trước đường liên kết để thông báo cho trình duyệt tải xuống sớm hơn bằng cách thêm phần tử Đường liên kết vào đầu tài liệu.

Thêm thẻ tải trước cho ứng dụng này:

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
</head>

Thuộc tính as dùng để xác định loại tài nguyên đang được tìm nạp và as="style" dùng để tải trước các tệp của bảng định kiểu.

Tải lại ứng dụng và xem bảng điều khiển Network (Mạng) trong DevTools.

Bảng điều khiển mạng có tài nguyên được tải trước

Hãy lưu ý cách trình duyệt tìm nạp tệp CSS trước khi JavaScript chịu trách nhiệm tìm nạp tệp đó thậm chí đã hoàn tất quá trình phân tích cú pháp. Với tính năng tải trước, trình duyệt sẽ biết cách tìm nạp trước tài nguyên với giả định rằng tài nguyên đó rất quan trọng đối với trang web.

Nếu không được sử dụng đúng cách, tính năng tải trước có thể gây hại cho hiệu suất bằng cách tạo các yêu cầu không cần thiết đối với các tài nguyên không được sử dụng. Trong ứng dụng này, details.css là một tệp CSS khác nằm ở thư mục gốc của dự án nhưng được dùng cho một /details route riêng biệt. Để minh hoạ ví dụ về cách sử dụng tính năng tải trước không chính xác, hãy thêm gợi ý tải trước cho tài nguyên này.

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
  <link rel="preload" href="details.css" as="style">
</head>

Tải lại ứng dụng và xem bảng điều khiển Network (Mạng). Một yêu cầu được thực hiện để truy xuất details.css mặc dù trang web không sử dụng tệp này.

Bảng điều khiển mạng có tải trước không cần thiết

Chrome sẽ hiển thị cảnh báo trong bảng điều khiển Console (Bảng điều khiển) khi trang không sử dụng tài nguyên được tải trước trong vòng vài giây sau khi tài nguyên đó tải xong.

Cảnh báo tải trước trong bảng điều khiển

Hãy sử dụng cảnh báo này làm chỉ báo để xác định xem trang web của bạn có tài nguyên nào được tải trước nhưng không được sử dụng ngay không. Giờ đây, bạn có thể xoá đường liên kết tải trước không cần thiết cho trang này.

<head>
  <!-- ... -->
  <link rel="preload" href="main.css" as="style">
  <link rel="preload" href="details.css" as="style">
</head>

Để biết danh sách tất cả các loại tài nguyên có thể được tìm nạp cùng với giá trị chính xác nên dùng cho thuộc tính as, hãy tham khảo bài viết của MDN về tính năng Tải trước.

Tìm nạp trước các tài nguyên trong tương lai

Tìm nạp trước là một gợi ý khác của trình duyệt có thể được dùng để tạo yêu cầu cho một thành phần được dùng cho một tuyến điều hướng khác nhưng có mức độ ưu tiên thấp hơn so với các thành phần quan trọng khác cần thiết cho trang hiện tại.

Trong trang web này, khi nhấp vào hình ảnh, bạn sẽ được chuyển đến một tuyến details/ riêng biệt.

Tuyến đường chi tiết

Một tệp CSS riêng biệt, details.css, chứa tất cả các kiểu cần thiết cho trang đơn giản này. Thêm một phần tử đường liên kết vào index.html để tải trước tài nguyên này.

<head>
  <!-- ... -->
  <link rel="prefetch" href="details.css">
</head>

Để hiểu cách thao tác này kích hoạt yêu cầu cho tệp, hãy mở bảng điều khiển Network (Mạng) trong DevTools và bỏ đánh dấu tuỳ chọn Disable cache (Tắt bộ nhớ đệm).

Tắt bộ nhớ đệm trong Công cụ của Chrome cho nhà phát triển

Tải lại ứng dụng và lưu ý cách một yêu cầu có mức độ ưu tiên rất thấp được thực hiện cho details.css sau khi tất cả các tệp khác đã được tìm nạp.

Bảng điều khiển mạng có tài nguyên được tìm nạp trước

Khi DevTools đang mở, hãy nhấp vào hình ảnh trên trang web để chuyển đến trang details. Vì phần tử đường liên kết được sử dụng trong details.html để tìm nạp details.css, nên một yêu cầu sẽ được thực hiện cho tài nguyên như dự kiến.

Yêu cầu mạng trên trang chi tiết

Nhấp vào yêu cầu mạng details.css trong DevTools để xem thông tin chi tiết. Bạn sẽ nhận thấy rằng tệp được truy xuất từ bộ nhớ đệm của ổ đĩa của trình duyệt.

Yêu cầu chi tiết được tìm nạp từ bộ nhớ đệm của ổ đĩa

Bằng cách tận dụng thời gian rảnh của trình duyệt, tính năng tải trước sẽ đưa ra yêu cầu sớm về tài nguyên cần thiết cho một trang khác. Điều này giúp tăng tốc các yêu cầu điều hướng trong tương lai bằng cách cho phép trình duyệt lưu tài sản vào bộ nhớ đệm sớm hơn và phân phát tài sản đó từ bộ nhớ đệm khi cần.

Tải trước và tìm nạp trước bằng webpack

Bài đăng Giảm tải trọng JavaScript bằng tính năng phân tách mã khám phá việc sử dụng tính năng nhập động để chia một gói thành nhiều phần. Điều này được minh hoạ bằng một ứng dụng đơn giản nhập linh động một mô-đun từ Lodash khi một biểu mẫu được gửi.

Ứng dụng Magic Sorter minh hoạ tính năng phân tách mã

Bạn có thể truy cập vào lỗi Glitch cho ứng dụng này tại đây.

Khối mã sau đây nằm trong src/index.js, chịu trách nhiệm nhập động phương thức khi người dùng nhấp vào nút.

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

Việc phân tách gói sẽ cải thiện thời gian tải trang bằng cách giảm kích thước ban đầu của gói. Phiên bản 4.6.0 của webpack hỗ trợ tải trước hoặc tải trước các đoạn được nhập một cách linh động. Lấy ứng dụng này làm ví dụ, phương thức lodash có thể được tìm nạp trước trong thời gian trình duyệt rảnh; khi người dùng nhấn nút, tài nguyên sẽ được tìm nạp mà không có độ trễ.

Sử dụng tham số nhận xét webpackPrefetch cụ thể trong một lệnh nhập động để tìm nạp trước một phần cụ thể. Dưới đây là giao diện của ứng dụng cụ thể này.

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

Sau khi tải lại ứng dụng, webpack sẽ chèn thẻ tìm nạp trước cho tài nguyên vào đầu tài liệu. Bạn có thể thấy điều này trong bảng điều khiển Elements (Phần tử) trong DevTools.

Bảng điều khiển phần tử có thẻ tải trước

Việc quan sát các yêu cầu trong bảng điều khiển Mạng cũng cho thấy rằng phần này được tìm nạp với mức độ ưu tiên thấp sau khi tất cả tài nguyên khác đã được yêu cầu.

Bảng điều khiển mạng có yêu cầu được tìm nạp trước

Mặc dù tính năng tải trước phù hợp hơn với trường hợp sử dụng này, nhưng webpack cũng hỗ trợ tải trước các phần được nhập linh động.

import(/* webpackPreload: true */ 'module')

Kết luận

Thông qua lớp học lập trình này, bạn sẽ hiểu rõ cách tải trước hoặc tải trước một số thành phần nhất định có thể cải thiện trải nghiệm người dùng trên trang web của bạn. Điều quan trọng cần đề cập là bạn không nên sử dụng các kỹ thuật này cho mọi tài nguyên và việc sử dụng không đúng cách có thể gây hại cho hiệu suất. Bạn sẽ nhận được kết quả tốt nhất bằng cách chỉ tải trước hoặc tải trước một cách có chọn lọc.

Tóm tắt:

  • Sử dụng tính năng tải trước cho các tài nguyên được phát hiện muộn nhưng rất quan trọng đối với trang hiện tại.
  • Sử dụng tính năng tìm nạp trước cho các tài nguyên cần thiết cho một tuyến đường điều hướng hoặc hành động của người dùng trong tương lai.

Không phải trình duyệt nào cũng hỗ trợ cả tính năng tải trước và tải trước. Điều này có nghĩa là không phải người dùng nào của ứng dụng cũng nhận thấy hiệu suất được cải thiện.

Nếu bạn muốn biết thêm thông tin về các khía cạnh cụ thể về cách tải trước và tải trước có thể ảnh hưởng đến trang web của bạn, hãy tham khảo các bài viết sau: