Tối ưu hoá hoạt động tải tài nguyên

Trong học phần trước, một số lý thuyết đằng sau đường dẫn hiển thị quan trọng là khám phá và cách các tài nguyên chặn hiển thị và chặn trình phân tích cú pháp có thể trì hoãn một sự kiện lần hiển thị ban đầu của trang. Giờ bạn đã hiểu một số lý thuyết Vậy là bạn đã sẵn sàng để tìm hiểu một số kỹ thuật để tối ưu hoá đường dẫn kết xuất.

Khi một trang tải, nhiều tài nguyên được tham chiếu trong HTML của trang đó cung cấp với giao diện và bố cục thông qua CSS, cũng như tính tương tác của trang thông qua JavaScript. Trong học phần này, một số khái niệm quan trọng liên quan đến chúng tôi sẽ đề cập đến các tài nguyên này và mức độ ảnh hưởng của chúng đối với thời gian tải của trang.

Chặn hiển thị

Như đã thảo luận trong mô-đun trước, CSS là một tài nguyên render-blocking, vì lệnh này chặn trình duyệt để không hiển thị bất kỳ nội dung nào cho đến Mô hình đối tượng CSS (CSSOM) đã được tạo. Trình duyệt chặn hiển thị để ngăn flash Nội dung không định kiểu (FOUC), đây là yếu tố không được mong muốn trên quan điểm trải nghiệm người dùng.

Trong video trước, có một FOUC ngắn để bạn có thể xem trang mà không cần bất kỳ kiểu nào. Sau đó, tất cả các kiểu sẽ được áp dụng sau khi CSS của trang đã đã tải xong từ mạng, và phiên bản chưa định kiểu của trang là ngay lập tức được thay thế bằng phiên bản được tạo kiểu.

Nói chung, FOUC là thứ bạn thường không thấy, nhưng đó là khái niệm là rất quan trọng để bạn biết lý do trình duyệt chặn hiển thị của trang cho đến khi CSS được tải xuống và áp dụng cho trang. Chặn hiển thị không hẳn là điều không như mong muốn nhưng bạn muốn giảm thiểu khoảng thời gian đảm bảo CSS của bạn được tối ưu hoá.

Chặn trình phân tích cú pháp

Tài nguyên chặn trình phân tích cú pháp sẽ làm gián đoạn trình phân tích cú pháp HTML, chẳng hạn như <script> không có thuộc tính async hoặc defer. Khi trình phân tích cú pháp gặp Phần tử <script>, trình duyệt cần đánh giá và thực thi tập lệnh trước tiếp tục phân tích cú pháp phần còn lại của HTML. Điều này là do thiết kế, vì tập lệnh có thể sửa đổi hoặc truy cập DOM trong khi vẫn đang được xây dựng.

<!-- This is a parser-blocking script: -->
<script src="/script.js"></script>

Khi sử dụng các tệp JavaScript bên ngoài (không có async hoặc defer), trình phân tích cú pháp sẽ cho đến khi tệp được tải xuống, phân tích cú pháp và thực thi. Khi bạn sử dụng JavaScript cùng dòng, trình phân tích cú pháp cũng bị chặn theo cách tương tự cho đến tập lệnh cùng dòng được phân tích cú pháp và thực thi.

Trình quét tải trước

Trình quét tải trước là một tính năng tối ưu hoá trình duyệt dưới dạng HTML phụ trình phân tích cú pháp quét phản hồi HTML thô để tìm và tìm nạp theo suy đoán trước khi trình phân tích cú pháp HTML chính phát hiện ra chúng. Cho ví dụ: trình quét tải trước sẽ cho phép trình duyệt bắt đầu tải xuống tệp tài nguyên được chỉ định trong phần tử <img>, ngay cả khi trình phân tích cú pháp HTML bị chặn trong khi tìm nạp và xử lý các tài nguyên như CSS và JavaScript.

Để tận dụng trình quét tải trước, bạn nên đưa các tài nguyên quan trọng vào trong mã đánh dấu HTML do máy chủ gửi. Các mẫu tải tài nguyên sau đây là không thể phát hiện bởi trình quét tải trước:

  • Hình ảnh do CSS tải bằng cách sử dụng thuộc tính background-image. Những hình ảnh này tệp đối chiếu có trong CSS và không thể phát hiện được bằng trình quét tải trước.
  • Các tập lệnh được tải động dưới dạng mã đánh dấu phần tử <script> được chèn vào DOM bằng cách sử dụng JavaScript hoặc các mô-đun được tải bằng import() động.
  • HTML được hiển thị trên ứng dụng bằng JavaScript. Mã đánh dấu như vậy có trong các chuỗi trong tài nguyên JavaScript và không thể tìm thấy được khi tải trước .
  • Khai báo CSS @import.

Các mẫu tải tài nguyên này đều là những tài nguyên được phát hiện muộn và do đó không được hưởng lợi từ trình quét tải trước. Hãy tránh sử dụng các thành phần này bất cứ khi nào có thể. Nếu không thể tránh được những mẫu đó, tuy nhiên, bạn có thể dùng Gợi ý preload để tránh chậm trễ trong việc khám phá tài nguyên.

CSS

CSS xác định cách trình bày và bố cục của trang. Như được mô tả trước đó, CSS là tài nguyên chặn hiển thị, vì vậy việc tối ưu hoá CSS có thể ảnh hưởng đáng kể đến tổng thời gian tải trang.

Thu nhỏ

Việc rút gọn tệp CSS giúp giảm kích thước tệp của tài nguyên CSS, nhờ đó tải xuống nhanh hơn. Điều này được thực hiện chủ yếu bằng cách xoá nội dung khỏi tệp CSS nguồn chẳng hạn như dấu cách và các ký tự vô hình khác, cũng như xuất kết quả cho một tệp mới được tối ưu hoá:

/* Unminified CSS: */

/* Heading 1 */
h1 {
  font-size: 2em;
  color: #000000;
}

/* Heading 2 */
h2 {
  font-size: 1.5em;
  color: #000000;
}
/* Minified CSS: */
h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}

Về hình thức cơ bản nhất, giảm thiểu CSS là một cách tối ưu hoá hiệu quả có thể cải thiện FCP của trang web và thậm chí là LCP trong một số trường hợp. Các công cụ như các gói có thể tự động thực hiện việc tối ưu hoá này cho bạn trong phiên bản chính thức bản dựng.

Xoá CSS không dùng

Trước khi hiển thị bất kỳ nội dung nào, trình duyệt cần tải xuống và phân tích cú pháp tất cả biểu định kiểu. Thời gian cần thiết để hoàn tất phân tích cú pháp cũng bao gồm các kiểu mà không được sử dụng trên trang hiện tại. Nếu bạn đang sử dụng trình gói kết hợp tất cả CSS vào một tệp duy nhất, thì người dùng có thể tải nhiều CSS xuống hơn cần thiết để hiển thị trang hiện tại.

Để tìm hiểu CSS không dùng cho trang hiện tại, hãy sử dụng công cụ Mức độ phù hợp trong Chrome Công cụ cho nhà phát triển.

Ảnh chụp màn hình về công cụ xác định mức độ sử dụng trong Công cụ của Chrome cho nhà phát triển. Một tệp CSS được chọn trong ngăn dưới cùng, hiển thị một lượng đáng kể CSS không được sử dụng trong bố cục trang hiện tại.
Công cụ mức độ sử dụng trong Công cụ của Chrome cho nhà phát triển rất hữu ích cho việc phát hiện CSS (và JavaScript) không được trang hiện tại sử dụng. Bạn có thể dùng công cụ này để chia các tệp CSS vào nhiều tài nguyên để tải trên các trang khác nhau, thay vì thì việc vận chuyển một gói CSS lớn hơn nhiều có thể làm chậm trễ việc hiển thị trang.

Việc xoá CSS không sử dụng có tác động gấp đôi: ngoài việc giảm số lượt tải xuống bạn đang tối ưu hoá việc xây dựng cây kết xuất, vì trình duyệt cần xử lý ít quy tắc CSS hơn.

Tránh khai báo CSS @import

Mặc dù việc này có vẻ thuận tiện, nhưng bạn nên tránh khai báo @import trong CSS:

/* Don't do this: */
@import url('style.css');

Tương tự như cách hoạt động của phần tử <link> trong HTML, phần khai báo @import trong CSS cho phép bạn nhập tài nguyên CSS bên ngoài từ trong biểu định kiểu. Chiến lược phát hành đĩa đơn Sự khác biệt chính giữa hai phương pháp này là phần tử HTML <link> là một phần của phản hồi HTML và do đó được phát hiện sớm hơn nhiều so với CSS là tệp khai báo @import tải xuống.

Lý do là để khai báo @import mà bạn phát hiện thấy, tệp CSS chứa tệp đó phải được tải xuống trước tiên. Chiến dịch này dẫn đến một chuỗi yêu cầu bị trì hoãn trong trường hợp CSS thời gian cần thiết để một trang hiển thị lần đầu. Một nhược điểm khác là không thể phát hiện các biểu định kiểu được tải bằng cách sử dụng khai báo @import bằng tải trước trình quét, từ đó trở thành tài nguyên chặn hiển thị được phát hiện muộn.

<!-- Do this instead: -->
<link rel="stylesheet" href="style.css">

Trong hầu hết các trường hợp, bạn có thể thay thế @import bằng cách sử dụng Phần tử <link rel="stylesheet">. Phần tử <link> cho phép biểu định kiểu được tải xuống đồng thời và giảm tổng thời gian tải, so với @import để tải các tờ khai định kiểu xuống liên tục.

CSS quan trọng cùng dòng

Thời gian cần để tải các tệp CSS xuống có thể làm tăng FCP của trang. Cùng dòng kiểu quan trọng trong tài liệu <head> loại bỏ yêu cầu mạng cho và khi được thực hiện đúng cách, tài nguyên CSS có thể cải thiện thời gian tải ban đầu khi bộ nhớ đệm trên trình duyệt của người dùng chưa được chuẩn bị. CSS còn lại có thể tải được không đồng bộ hoặc được thêm vào cuối phần tử <body>.

<head>
  <title>Page Title</title>
  <!-- ... -->
  <style>h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}</style>
</head>
<body>
  <!-- Other page markup... -->
  <link rel="stylesheet" href="non-critical.css">
</body>

Tuy nhiên, nhược điểm là việc đặt một lượng lớn CSS cùng dòng sẽ thêm nhiều byte hơn vào phần đầu Phản hồi HTML. Bởi vì tài nguyên HTML thường không thể được lưu vào bộ nhớ đệm trong thời gian quá dài—hoặc tại tất cả—điều này có nghĩa là CSS cùng dòng không được lưu vào bộ nhớ đệm cho các trang tiếp theo mà có thể sử dụng cùng một CSS trong các biểu định kiểu bên ngoài. Kiểm tra và đo lường hiệu suất để đảm bảo đánh đổi xứng đáng với công sức bỏ ra.

Bản minh hoạ CSS

JavaScript

JavaScript thúc đẩy hầu hết các hoạt động tương tác trên web nhưng phải trả phí. Việc vận chuyển quá nhiều JavaScript có thể làm cho trang web của bạn phản hồi chậm trong trang tải và thậm chí có thể gây ra sự cố về thời gian phản hồi làm chậm tương tác — cả hai có thể gây khó chịu cho người dùng.

JavaScript chặn hiển thị

Khi tải các phần tử <script> mà không có thuộc tính defer hoặc async, trình duyệt chặn phân tích cú pháp và hiển thị cho đến khi tập lệnh được tải xuống, phân tích cú pháp và thực thi. Tương tự, tập lệnh cùng dòng chặn trình phân tích cú pháp cho đến khi tập lệnh được phân tích cú pháp và thực thi.

async đấu với defer

asyncdefer cho phép các tập lệnh bên ngoài tải mà không chặn HTML trình phân tích cú pháp trong khi các tập lệnh (bao gồm cả tập lệnh cùng dòng) với type="module" là tự động được hoãn lại. Tuy nhiên, asyncdefer có một số điểm khác biệt là điều quan trọng cần hiểu.

Hình mô tả nhiều cơ chế tải tập lệnh, tất cả nêu chi tiết vai trò trình phân tích cú pháp, tìm nạp và thực thi dựa trên nhiều thuộc tính được dùng như async,Defer, type=&#39;module&#39; và sự kết hợp của cả ba.
Nguồn: https://html.spec.whatwg.org/multipage/scripting.html

Những tập lệnh tải bằng async được phân tích cú pháp và thực thi ngay sau khi được tải xuống. trong khi những tập lệnh được tải bằng defer sẽ được thực thi khi phân tích cú pháp tài liệu HTML được hoàn tất—việc này xảy ra cùng lúc với sự kiện DOMContentLoaded của trình duyệt. Ngoài ra, tập lệnh async có thể thực thi không đúng thứ tự, trong khi tập lệnh defer được thực thi theo thứ tự mà chúng xuất hiện trong thẻ đánh dấu.

Hiển thị phía máy khách

Nói chung, bạn nên tránh sử dụng JavaScript để hiển thị bất kỳ nội dung quan trọng nào hoặc phần tử LCP của trang. Đây được gọi là hiển thị phía máy khách và là một kỹ thuật được sử dụng rộng rãi trong các ứng dụng trang đơn (SPA).

Đánh dấu được hiển thị bằng JavaScript đi qua trình quét tải trước dưới dạng tài nguyên có trong mã đánh dấu do ứng dụng hiển thị không thể phát hiện được. Chiến dịch này có thể trì hoãn việc tải các tài nguyên quan trọng xuống, chẳng hạn như hình ảnh LCP. Trình duyệt chỉ bắt đầu tải hình ảnh LCP xuống sau khi tập lệnh đã thực thi và thêm phần tử vào DOM. Đổi lại, tập lệnh chỉ có thể được thực thi sau khi được khám phá, tải xuống và phân tích cú pháp. Đây gọi là yêu cầu quan trọng mà bạn nên tránh.

Ngoài ra, việc kết xuất mã đánh dấu bằng JavaScript có nhiều khả năng tạo ra các nhiệm vụ dài so với mã đánh dấu được tải xuống từ máy chủ để phản hồi một thao tác điều hướng của bạn. Việc sử dụng rộng rãi tính năng hiển thị HTML phía máy khách có thể ảnh hưởng tiêu cực độ trễ tương tác. Điều này đặc biệt đúng trong những trường hợp mà DOM của một trang rất lớn, kích hoạt công việc kết xuất đáng kể khi JavaScript sửa đổi DOM.

Thu nhỏ

Tương tự như CSS, việc giảm bớt JavaScript sẽ giảm kích thước tệp của tài nguyên tập lệnh. Điều này có thể giúp tải xuống nhanh hơn, cho phép trình duyệt chuyển sang phân tích cú pháp và biên dịch JavaScript nhanh hơn.

Ngoài ra, việc giảm kích thước JavaScript còn tiến xa hơn một bước so với việc giảm kích thước các thành phần khác, chẳng hạn như CSS. Khi JavaScript được giảm thiểu, nó không chỉ bị xoá về những mục như dấu cách, thẻ và nhận xét nhưng ký hiệu trong nguồn JavaScript được rút ngắn. Quá trình này đôi khi được gọi là không sử dụng được. Người nhận thấy sự khác biệt, hãy lấy mã nguồn JavaScript sau:

// Unuglified JavaScript source code:
export function injectScript () {
  const scriptElement = document.createElement('script');
  scriptElement.src = '/js/scripts.js';
  scriptElement.type = 'module';

  document.body.appendChild(scriptElement);
}

Khi mã nguồn JavaScript trước đó không chính xác, kết quả có thể trông chẳng hạn như đoạn mã sau:

// Uglified JavaScript production code:
export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}

Trong đoạn mã trước, bạn có thể thấy rằng biến mà con người có thể đọc được scriptElement trong nguồn được rút ngắn thành t. Khi được áp dụng trên một phạm vi lớn tập hợp tập lệnh, thì khoản tiết kiệm có thể khá đáng kể mà không ảnh hưởng đến các tính năng mà JavaScript sản xuất của trang web cung cấp.

Nếu bạn đang sử dụng trình theo gói để xử lý mã nguồn của trang web, hãy chọn không hợp lệ thường được thực hiện tự động cho các bản dựng chính thức. Đơn vị quảng cáo — chẳng hạn như Terser, ví dụ: — cũng có thể định cấu hình cao, cho phép bạn tinh chỉnh mức độ linh hoạt của thuật toán đơn giản hoá để tiết kiệm tối đa. Tuy nhiên, các chế độ mặc định cho mọi công cụ loại bỏ thông thường là đủ để cảnh cáo sự cân bằng hợp lý giữa kích thước đầu ra và khả năng duy trì.

Bản minh hoạ JavaScript

Kiểm tra kiến thức của bạn

Cách tốt nhất để tải nhiều tệp CSS trong trình duyệt là gì?

Nhiều phần tử <link>.
Nội dung khai báo @import của CSS.

Trình quét tải trước của trình duyệt làm gì?

Phát hiện phần tử <link rel="preload"> trong tài nguyên HTML.
Đây là một trình phân tích cú pháp HTML phụ, kiểm tra thẻ đánh dấu thô để phát hiện trước khi trình phân tích cú pháp DOM có thể phát hiện chúng sớm hơn.

Tại sao theo mặc định, trình duyệt tạm thời chặn quá trình phân tích cú pháp HTML khi tải các tài nguyên JavaScript xuống?

Để ngăn hiện tượng Flash nội dung không theo kiểu (FOUC).
Vì tập lệnh có thể sửa đổi hoặc truy cập vào DOM.
Vì việc đánh giá JavaScript là một tác vụ tiêu tốn rất nhiều CPU và việc tạm dừng Quá trình phân tích cú pháp HTML cung cấp thêm băng thông cho CPU để hoàn tất việc tải tập lệnh.

Tiếp theo: Hỗ trợ trình duyệt bằng các gợi ý về tài nguyên

Giờ đây, bạn đã nắm được cách tải tài nguyên trong phần tử <head> ảnh hưởng đến tải trang ban đầu và các chỉ số khác nhau, đã đến lúc tiếp tục. Trong thời gian tới mô-đun, gợi ý về tài nguyên được khám phá và cách chúng có thể đưa ra gợi ý có giá trị trình duyệt để bắt đầu tải tài nguyên và mở các kết nối đến nhiều nguồn gốc sớm hơn trình duyệt nếu không có chúng.