Tối ưu hoá thời gian phản hồi lần tương tác đầu tiên

Cách phản hồi nhanh hơn với hoạt động tương tác của người dùng.

Tôi đã nhấp nhưng không có gì xảy ra! Tại sao tôi không tương tác được với trang này? 😢

Thời gian hiển thị nội dung đầu tiên (FCP) và Thời gian hiển thị nội dung lớn nhất (LCP) là hai chỉ số đo lường thời gian cần để nội dung hiển thị (hiển thị) (hiển thị) một cách trực quan trên một trang. Mặc dù quan trọng, nhưng thời gian hiển thị không phản ánh mức độ phản hồi của lượt tải: hoặc tốc độ trang phản hồi với tương tác của người dùng.

Thời gian phản hồi lần tương tác đầu tiên (FID) là một chỉ số Các chỉ số quan trọng về trang web ghi lại ấn tượng đầu tiên của người dùng về mức độ tương tác và tốc độ phản hồi trên trang web. Chỉ số này đo lường thời gian từ khi người dùng tương tác lần đầu với một trang cho đến khi trình duyệt thực sự có thể phản hồi lượt tương tác đó. FID là một chỉ số trường và không thể mô phỏng trong môi trường phòng thí nghiệm. Sự tương tác thực tế của người dùng là yêu cầu bắt buộc để đo lường độ trễ phản hồi.

Giá trị FI tốt là 2,5 giây, giá trị kém lớn hơn 4,0 giây và bất kỳ điều gì ở giữa cần cải thiện

Để giúp dự đoán FID trong phòng thí nghiệm, bạn nên sử dụng Tổng thời gian chặn (TBT). Các chỉ số này đo lường nhiều yếu tố khác nhau, nhưng những điểm cải thiện trong TBT thường tương ứng với sự cải thiện về FID.

Nguyên nhân chính gây ra FID kém là thực thi JavaScript nặng. Việc tối ưu hoá cách JavaScript phân tích cú pháp, biên dịch và thực thi trên trang web của bạn sẽ trực tiếp làm giảm FID.

Thực thi JavaScript nhiều

Trình duyệt không thể phản hồi hầu hết hoạt động đầu vào của người dùng trong khi đang thực thi JavaScript trên luồng chính. Nói cách khác, trình duyệt không thể phản hồi các tương tác của người dùng trong khi luồng chính đang bận. Để cải thiện vấn đề này, hãy làm như sau:

Chia nhỏ các Tác vụ dài

Nếu đã cố gắng giảm số lượng JavaScript tải trên một trang, thì bạn nên chia nhỏ mã chạy trong thời gian dài thành các tác vụ nhỏ hơn và không đồng bộ.

Tác vụ dài là các giai đoạn thực thi JavaScript mà người dùng có thể thấy giao diện người dùng của bạn không phản hồi. Bất kỳ đoạn mã nào chặn luồng chính trong 50 mili giây trở lên đều có thể được mô tả là Tác vụ dài. Tác vụ dài là dấu hiệu cho thấy tình trạng JavaScript có thể tăng lên (tải và thực thi nhiều hơn mức mà người dùng có thể cần ngay bây giờ). Việc chia nhỏ các tác vụ dài có thể giảm độ trễ đầu vào trên trang web của bạn.

Tác vụ dài trong Công cụ của Chrome cho nhà phát triển
Công cụ của Chrome cho nhà phát triển hiển thị các Tác vụ dài trong Bảng điều khiển hiệu suất

FID sẽ cải thiện đáng kể khi bạn áp dụng các phương pháp hay nhất như phân tách mã và chia nhỏ các Tác vụ dài. Mặc dù TBT không phải là một chỉ số trường, nhưng nó rất hữu ích để kiểm tra tiến trình nhằm cải thiện cả Thời gian tương tác (TTI) và FID.

Tối ưu hoá trang để đảm bảo mức độ sẵn sàng tương tác

Có một số nguyên nhân phổ biến dẫn đến điểm FID và TBT thấp trong các ứng dụng web phụ thuộc nhiều vào JavaScript:

Việc thực thi tập lệnh của bên thứ nhất có thể trì hoãn trạng thái sẵn sàng tương tác

  • Kích thước JavaScript tăng lên, thời gian thực thi nặng nề và việc phân đoạn không hiệu quả có thể làm chậm khoảng thời gian một trang có thể phản hồi hoạt động đầu vào của người dùng cũng như tác động đến FID, TBT và TTI. Việc tải dần mã và các tính năng có thể giúp phân bổ công việc này và cải thiện mức độ sẵn sàng tương tác.
  • Các ứng dụng kết xuất phía máy chủ có thể trông giống như các pixel nhanh chóng được vẽ trên màn hình, nhưng hãy lưu ý rằng các hoạt động tương tác của người dùng bị chặn bởi các quá trình thực thi tập lệnh lớn (ví dụ: tái nước để kết nối với trình nghe sự kiện). Quá trình này có thể mất vài trăm mili giây, đôi khi thậm chí là vài giây, nếu bạn đang sử dụng tính năng phân tách mã dựa trên tuyến. Hãy cân nhắc thay đổi nhiều logic hơn phía máy chủ hoặc tạo thêm nội dung tĩnh trong thời gian xây dựng.

Dưới đây là điểm TBT trước và sau khi tối ưu hoá quá trình tải tập lệnh của bên thứ nhất cho một ứng dụng. Bằng cách di chuyển hoạt động tải (và thực thi) tập lệnh tốn kém cho một thành phần không thiết yếu ra khỏi đường dẫn quan trọng, người dùng có thể tương tác với trang sớm hơn nhiều.

Những cải tiến về điểm TBT trong Lighthouse sau khi tối ưu hoá tập lệnh của bên thứ nhất.

Quá trình tìm nạp dữ liệu có thể tác động đến nhiều khía cạnh của mức độ sẵn sàng tương tác

  • Việc chờ một hệ thống tìm nạp theo tầng (ví dụ: JavaScript và tìm nạp dữ liệu cho các thành phần) có thể ảnh hưởng đến độ trễ tương tác. Nhằm giảm thiểu sự phụ thuộc vào phương thức tìm nạp dữ liệu theo tầng.
  • Các kho dữ liệu lớn cùng dòng có thể đưa ra thời gian phân tích cú pháp HTML và tác động đến cả chỉ số vẽ và tương tác. Mục đích là giảm thiểu lượng dữ liệu cần được xử lý sau ở phía máy khách.

Việc thực thi tập lệnh của bên thứ ba cũng có thể làm chậm độ trễ tương tác

  • Nhiều trang web sử dụng thẻ và số liệu phân tích của bên thứ ba. Điều này có thể khiến mạng bận và khiến luồng chính định kỳ không phản hồi, ảnh hưởng đến độ trễ tương tác. Khám phá tính năng tải mã bên thứ ba theo yêu cầu (ví dụ: có thể không tải các quảng cáo dưới màn hình đầu tiên cho đến khi chúng được cuộn đến gần khung nhìn hơn).
  • Trong một số trường hợp, các tập lệnh của bên thứ ba có thể giành trước các tập lệnh của bên thứ nhất về mức độ ưu tiên và băng thông trên luồng chính, đồng thời trì hoãn thời gian một trang sẵn sàng tương tác. Cố gắng tải những nội dung mà bạn tin rằng sẽ mang lại giá trị lớn nhất cho người dùng trước tiên.

Sử dụng trình chạy web

Luồng chính bị chặn là một trong những nguyên nhân chính gây ra độ trễ đầu vào. Trình chạy web giúp bạn có thể chạy JavaScript trên luồng trong nền. Việc di chuyển các hoạt động không phải giao diện người dùng sang một luồng worker riêng có thể làm giảm thời gian chặn luồng chính, từ đó cải thiện FID.

Hãy cân nhắc sử dụng các thư viện sau đây để giúp bạn sử dụng worker trên trang web dễ dàng hơn:

  • Comlink: Một thư viện trợ giúp giúp tóm tắt postMessage và giúp bạn dễ sử dụng hơn
  • Workway: Một trình xuất trình chạy web cho mục đích chung
  • Workerize: Di chuyển mô-đun vào trình thực thi web

Giảm thời gian thực thi JavaScript

Việc giới hạn số lượng JavaScript trên trang của bạn sẽ giúp giảm lượng thời gian mà trình duyệt cần dành cho việc thực thi mã JavaScript. Điều này giúp tăng tốc độ của trình duyệt để phản hồi mọi tương tác của người dùng.

Để giảm số lượng JavaScript được thực thi trên trang của bạn:

  • Hoãn JavaScript không dùng đến
  • Giảm thiểu polyfills không sử dụng

Hoãn JavaScript không dùng đến

Theo mặc định, tất cả JavaScript đều chặn hiển thị. Khi gặp một thẻ tập lệnh liên kết đến tệp JavaScript bên ngoài, trình duyệt sẽ phải tạm dừng hoạt động đang thực hiện cũng như tải xuống, phân tích cú pháp, biên dịch và thực thi JavaScript đó. Do đó, bạn chỉ nên tải mã cần thiết cho trang hoặc mã phản hồi hoạt động đầu vào của người dùng.

Thẻ Phạm vi lập chỉ mục trong Công cụ của Chrome cho nhà phát triển có thể cho bạn biết mức độ JavaScript hiện không được sử dụng trên trang web của bạn.

Thẻ Mức độ phù hợp.

Cách giảm bớt JavaScript không dùng đến:

  • Chia gói của bạn thành nhiều phần
  • Trì hoãn mọi JavaScript không quan trọng, bao gồm cả các tập lệnh của bên thứ ba, bằng cách sử dụng async hoặc defer

Phân tách mã là khái niệm về việc chia một gói JavaScript lớn thành các phần nhỏ hơn có thể tải theo điều kiện (còn gọi là tải từng phần). Hầu hết các trình duyệt mới đều hỗ trợ cú pháp nhập động, cho phép tìm nạp mô-đun theo yêu cầu:

import('module.js').then((module) => {
  // Do something with the module.
});

Việc nhập JavaScript một cách linh động trên một số hoạt động tương tác của người dùng (chẳng hạn như thay đổi tuyến hoặc hiển thị một phương thức) sẽ đảm bảo rằng mã không dùng cho lượt tải trang ban đầu chỉ được tìm nạp khi cần.

Ngoài việc hỗ trợ chung cho trình duyệt, bạn có thể sử dụng cú pháp nhập động trong nhiều hệ thống xây dựng.

  • Nếu bạn sử dụng webpack, Rollup hoặc Parcel làm trình đóng gói mô-đun, hãy tận dụng sự hỗ trợ của tính năng nhập động.
  • Các khung phía máy khách, như React, AngularVue cung cấp các bản tóm tắt để giúp bạn dễ dàng tải từng phần ở cấp thành phần hơn.

Ngoài việc phân tách mã, hãy luôn sử dụng chế độ không đồng bộ hoặc trì hoãn cho các tập lệnh không cần thiết đối với đường dẫn quan trọng hoặc nội dung trong màn hình đầu tiên.

<script defer src="…"></script>
<script async src="…"></script>

Trừ phi có lý do cụ thể để không làm như vậy, theo mặc định, tất cả tập lệnh của bên thứ ba đều phải được tải bằng defer hoặc async.

Giảm thiểu polyfills không sử dụng

Nếu bạn soạn thảo mã của mình bằng cú pháp JavaScript hiện đại và tham chiếu đến các API của trình duyệt hiện đại, bạn sẽ cần phải dịch mã và thêm các đoạn mã polyfill để mã hoạt động được trong những trình duyệt cũ hơn.

Một trong những mối lo ngại chính về hiệu suất khi thêm polyfill và mã đã chuyển đổi vào trang web của bạn là các trình duyệt mới không cần phải tải mã xuống nếu không cần. Để giảm kích thước JavaScript của ứng dụng, hãy giảm thiểu các polyfills không dùng đến ở mức tối đa và hạn chế sử dụng ở những môi trường cần thiết.

Cách tối ưu hoá việc sử dụng polyfill trên trang web của bạn:

  • Nếu bạn dùng Babel làm bộ chuyển đổi, hãy sử dụng @babel/preset-env để chỉ thêm các polyfill cần thiết cho các trình duyệt mà bạn định nhắm mục tiêu. Đối với CameraX 7.9, hãy bật tuỳ chọn bugfixes để giảm bớt mọi polyfill không cần thiết
  • Sử dụng mẫu mô-đun/không mô-đun để phân phối hai gói riêng biệt (@babel/preset-env cũng hỗ trợ việc này qua target.esmodules)

    <script type="module" src="modern.js"></script>
    <script nomodule src="legacy.js" defer></script>
    

    Nhiều tính năng ECMAScript mới hơn được biên dịch bằng Bumblebee đã được hỗ trợ trong các môi trường hỗ trợ các mô-đun JavaScript. Vì vậy, bằng cách làm như vậy, bạn sẽ đơn giản hoá quá trình đảm bảo rằng chỉ các trình duyệt đã chuyển mã mới được dùng cho những trình duyệt thực sự cần mã đó.

Công cụ dành cho nhà phát triển

Có một số công cụ để đo lường và gỡ lỗi FID:

Xin cảm ơn những bài đánh giá của Philip Walton, Kayce Basques, Ilya Grigorik và Annie Sullivan.