Tối ưu hoá tương tác cho thời gian hiển thị tiếp theo

Tìm hiểu cách tối ưu hoá chỉ số Lượt tương tác đến nội dung hiển thị tiếp theo của trang web.

Lượt tương tác đến nội dung hiển thị tiếp theo (INP) là một chỉ số ổn định trong Chỉ số quan trọng chính của trang web. Chỉ số này đánh giá khả năng thích ứng tổng thể của một trang đối với hoạt động tương tác của người dùng bằng cách quan sát độ trễ của tất cả lượt tương tác đủ điều kiện xảy ra trong suốt thời gian người dùng truy cập vào một trang. Giá trị INP cuối cùng tương ứng với lượt tương tác dài nhất quan sát được (đôi khi bỏ qua các điểm ngoại lai).

Để mang lại trải nghiệm tốt cho người dùng, các trang web nên cố gắng để có được chỉ số Lượt tương tác đến nội dung hiển thị tiếp theo là 200 mili giây trở xuống. Để đảm bảo bạn đang đạt được mục tiêu này cho hầu hết người dùng, ngưỡng phù hợp để đo lường là tỷ lệ phần trăm thứ 75 của số lượt tải trang, được phân đoạn trên thiết bị di động và máy tính.

Giá trị INP tốt là dưới 200 mili giây, giá trị kém là trên 500 mili giây và mọi giá trị ở giữa cần được cải thiện.

Tuỳ thuộc vào trang web, có thể có ít hoặc không có hoạt động tương tác nào, chẳng hạn như các trang chủ yếu chứa văn bản và hình ảnh với ít hoặc không có thành phần tương tác nào. Hoặc trong trường hợp các trang web như trình chỉnh sửa văn bản hoặc trò chơi, có thể có hàng trăm, thậm chí hàng nghìn lượt tương tác. Trong cả hai trường hợp, khi INP cao, trải nghiệm người dùng sẽ gặp rủi ro.

Bạn cần phải dành thời gian và công sức để cải thiện INP, nhưng phần thưởng là trải nghiệm người dùng tốt hơn. Trong hướng dẫn này, chúng ta sẽ tìm hiểu lộ trình cải thiện INP.

Tìm hiểu nguyên nhân gây ra INP kém

Trước khi có thể khắc phục tình trạng tương tác chậm, bạn cần có dữ liệu để biết liệu INP của trang web có kém hay cần cải thiện hay không. Sau khi có thông tin đó, bạn có thể chuyển sang phòng thí nghiệm để bắt đầu chẩn đoán các lượt tương tác bị chậm và tìm giải pháp.

Tìm các lượt tương tác chậm trong trường

Tốt nhất là bạn nên bắt đầu hành trình tối ưu hoá INP bằng dữ liệu trường. Ở mức tốt nhất, dữ liệu trường từ nhà cung cấp dịch vụ Theo dõi người dùng thực (RUM) sẽ không chỉ cung cấp cho bạn giá trị INP của một trang mà còn cung cấp dữ liệu theo bối cảnh làm nổi bật lượt tương tác cụ thể nào chịu trách nhiệm cho giá trị INP đó, liệu lượt tương tác đó có xảy ra trong hoặc sau khi tải trang, loại lượt tương tác (nhấp, nhấn phím hoặc nhấn) và các thông tin có giá trị khác.

Nếu bạn không dựa vào nhà cung cấp RUM để lấy dữ liệu thực tế, thì hướng dẫn về dữ liệu thực tế INP khuyên bạn nên sử dụng Báo cáo trải nghiệm người dùng trên Chrome (CrUX) thông qua PageSpeed Insights để bổ sung dữ liệu còn thiếu. CrUX là tập dữ liệu chính thức của chương trình Chỉ số quan trọng chính của trang web và cung cấp thông tin tóm tắt cấp cao về các chỉ số cho hàng triệu trang web, bao gồm cả INP. Tuy nhiên, CrUX thường không cung cấp dữ liệu theo ngữ cảnh mà bạn nhận được từ nhà cung cấp RUM để giúp bạn phân tích các vấn đề. Do đó, các trang web vẫn nên sử dụng nhà cung cấp RUM khi có thể hoặc triển khai giải pháp RUM của riêng mình để bổ sung cho những gì có trong CrUX.

Chẩn đoán các hoạt động tương tác chậm trong phòng thí nghiệm

Tốt nhất là bạn nên bắt đầu thử nghiệm trong phòng thí nghiệm sau khi có dữ liệu thực địa cho thấy bạn có các lượt tương tác chậm. Khi không có dữ liệu thực địa, bạn có thể sử dụng một số chiến lược để xác định các lượt tương tác chậm trong phòng thí nghiệm. Các chiến lược như vậy bao gồm việc theo dõi luồng người dùng phổ biến và kiểm thử các lượt tương tác trong quá trình đó, cũng như tương tác với trang trong khi tải (khi luồng chính thường bận nhất) để hiển thị các lượt tương tác chậm trong phần quan trọng đó của trải nghiệm người dùng.

Tối ưu hoá lượt tương tác

Sau khi bạn xác định được một lượt tương tác chậm và có thể tái tạo lượt tương tác đó theo cách thủ công trong phòng thí nghiệm, bước tiếp theo là tối ưu hoá lượt tương tác đó. Có thể chia các lượt tương tác thành 3 giai đoạn:

  1. Độ trễ đầu vào bắt đầu khi người dùng bắt đầu tương tác với trang và kết thúc khi lệnh gọi lại sự kiện cho lượt tương tác bắt đầu chạy.
  2. Thời gian xử lý, bao gồm thời gian cần thiết để lệnh gọi lại sự kiện chạy xong.
  3. Độ trễ hiển thị, là thời gian cần thiết để trình duyệt hiển thị khung hình tiếp theo chứa kết quả hình ảnh của lượt tương tác.

Tổng của ba giai đoạn này là tổng độ trễ tương tác. Mỗi giai đoạn của một lượt tương tác đều góp phần tạo ra một khoảng thời gian nhất định cho tổng độ trễ của lượt tương tác. Vì vậy, bạn cần biết cách tối ưu hoá từng phần của lượt tương tác để lượt tương tác đó chạy trong thời gian ngắn nhất có thể.

Xác định và giảm độ trễ khi nhập

Khi người dùng tương tác với một trang, phần đầu tiên của lượt tương tác đó là độ trễ đầu vào. Tuỳ thuộc vào hoạt động khác trên trang, độ trễ đầu vào có thể kéo dài đáng kể. Điều này có thể là do hoạt động xảy ra trên luồng chính (có thể là do các tập lệnh tải, phân tích cú pháp và biên dịch), xử lý tìm nạp, hàm hẹn giờ hoặc thậm chí là do các hoạt động tương tác khác xảy ra liên tiếp và chồng chéo lên nhau.

Bất kể nguồn gốc của độ trễ đầu vào của một lượt tương tác là gì, bạn cũng nên giảm độ trễ đầu vào xuống mức tối thiểu để các lượt tương tác có thể bắt đầu chạy lệnh gọi lại sự kiện càng sớm càng tốt.

Mối quan hệ giữa việc đánh giá tập lệnh và các tác vụ dài trong quá trình khởi động

Một khía cạnh quan trọng của tính tương tác trong vòng đời của trang là trong quá trình khởi động. Khi tải, trang sẽ hiển thị ban đầu, nhưng điều quan trọng cần nhớ là việc trang hiển thị không có nghĩa là trang đã hoàn tất quá trình tải. Tuỳ thuộc vào số lượng tài nguyên mà một trang cần để hoạt động đầy đủ, người dùng có thể cố gắng tương tác với trang trong khi trang vẫn đang tải.

Một điều có thể kéo dài độ trễ đầu vào của lượt tương tác trong khi trang tải là việc đánh giá tập lệnh. Sau khi một tệp JavaScript được tìm nạp từ mạng, trình duyệt vẫn còn việc phải làm trước khi JavaScript đó có thể chạy; công việc đó bao gồm việc phân tích cú pháp một tập lệnh để đảm bảo cú pháp của tập lệnh đó hợp lệ, biên dịch tập lệnh đó thành mã byte và cuối cùng là thực thi tập lệnh đó.

Tuỳ thuộc vào kích thước của tập lệnh, công việc này có thể đưa ra các tác vụ dài trên luồng chính, khiến trình duyệt bị chậm trễ trong việc phản hồi các hoạt động tương tác khác của người dùng. Để trang của bạn luôn phản hồi hoạt động đầu vào của người dùng trong khi tải trang, điều quan trọng là bạn phải hiểu những việc bạn có thể làm để giảm khả năng xảy ra các tác vụ dài trong khi tải trang, nhờ đó trang luôn nhanh chóng.

Tối ưu hoá lệnh gọi lại sự kiện

Độ trễ đầu vào chỉ là phần đầu tiên của những gì INP đo lường. Bạn cũng cần đảm bảo rằng các lệnh gọi lại sự kiện chạy để phản hồi hoạt động tương tác của người dùng có thể hoàn tất nhanh nhất có thể.

Thường xuyên nhường cho luồng chính

Lời khuyên chung tốt nhất để tối ưu hoá lệnh gọi lại sự kiện là làm ít việc nhất có thể trong các lệnh gọi đó. Tuy nhiên, logic tương tác của bạn có thể phức tạp và bạn chỉ có thể giảm nhẹ công việc mà các thành phần đó thực hiện.

Nếu thấy trang web của mình gặp phải trường hợp này, việc tiếp theo bạn có thể thử là chia nhỏ công việc trong lệnh gọi lại sự kiện thành các tác vụ riêng biệt. Điều này giúp công việc tập thể không trở thành một tác vụ dài hạn chặn luồng chính, cho phép các hoạt động tương tác khác chạy sớm hơn so với khi phải chờ luồng chính.

setTimeout là một cách để chia nhỏ các tác vụ, vì lệnh gọi lại được truyền vào đó sẽ chạy trong một tác vụ mới. Bạn có thể sử dụng riêng setTimeout hoặc trừu tượng hoá việc sử dụng hàm này thành một hàm riêng để có được kết quả phù hợp hơn với người dùng.

Việc trả về một cách không phân biệt tốt hơn so với việc không trả về. Tuy nhiên, có một cách tinh tế hơn để trả về luồng chính, và cách này chỉ liên quan đến việc trả về ngay sau lệnh gọi lại sự kiện cập nhật giao diện người dùng để logic kết xuất có thể chạy sớm hơn.

Cung cấp để cho phép công việc kết xuất diễn ra sớm hơn

Một kỹ thuật nhường quyền nâng cao hơn liên quan đến việc sắp xếp mã trong lệnh gọi lại sự kiện để giới hạn những gì được chạy chỉ bằng logic cần thiết để áp dụng các bản cập nhật hình ảnh cho khung hình tiếp theo. Mọi thứ khác có thể được trì hoãn cho một tác vụ tiếp theo. Điều này không chỉ giúp lệnh gọi lại nhẹ nhàng và linh hoạt mà còn cải thiện thời gian kết xuất cho các lượt tương tác bằng cách không cho phép các bản cập nhật hình ảnh chặn mã gọi lại sự kiện.

Ví dụ: hãy tưởng tượng một trình soạn thảo văn bản đa dạng thức định dạng văn bản khi bạn nhập, nhưng cũng cập nhật các khía cạnh khác của giao diện người dùng để phản hồi nội dung bạn đã viết (chẳng hạn như số từ, làm nổi bật lỗi chính tả và các phản hồi trực quan quan trọng khác). Ngoài ra, ứng dụng cũng có thể cần lưu nội dung bạn đã viết để nếu bạn rời khỏi và quay lại, bạn sẽ không mất bất kỳ công việc nào.

Trong ví dụ này, 4 việc sau cần xảy ra để phản hồi các ký tự do người dùng nhập. Tuy nhiên, bạn chỉ cần thực hiện mục đầu tiên trước khi khung tiếp theo xuất hiện.

  1. Cập nhật hộp văn bản bằng nội dung người dùng đã nhập và áp dụng mọi định dạng bắt buộc.
  2. Cập nhật phần giao diện người dùng hiển thị số từ hiện tại.
  3. Chạy logic để kiểm tra lỗi chính tả.
  4. Lưu các thay đổi gần đây nhất (ở cục bộ hoặc vào cơ sở dữ liệu từ xa).

Mã để thực hiện việc này có thể có dạng như sau:

textBox.addEventListener('input', (inputEvent) => {
  // Update the UI immediately, so the changes the user made
  // are visible as soon as the next frame is presented.
  updateTextBox(inputEvent);

  // Use `setTimeout` to defer all other work until at least the next
  // frame by queuing a task in a `requestAnimationFrame()` callback.
  requestAnimationFrame(() => {
    setTimeout(() => {
      const text = textBox.textContent;
      updateWordCount(text);
      checkSpelling(text);
      saveChanges(text);
    }, 0);
  });
});

Hình ảnh trực quan sau đây cho thấy cách trì hoãn mọi nội dung cập nhật không quan trọng cho đến sau khung hình tiếp theo có thể làm giảm thời lượng xử lý và do đó giảm độ trễ tương tác tổng thể.

Hình ảnh mô tả một lượt tương tác bằng bàn phím và các thao tác tiếp theo trong hai trường hợp. Trong hình trên cùng, tác vụ quan trọng về kết xuất và tất cả tác vụ trong nền tiếp theo chạy đồng bộ cho đến khi có cơ hội hiển thị khung. Trong hình dưới cùng, công việc quan trọng về kết xuất sẽ chạy trước, sau đó chuyển sang luồng chính để hiển thị khung mới sớm hơn. Các tác vụ trong nền sẽ chạy sau đó.
Nhấp vào hình trên để xem phiên bản có độ phân giải cao.

Mặc dù việc sử dụng setTimeout() bên trong lệnh gọi requestAnimationFrame() trong ví dụ về mã trước đó có vẻ hơi khó hiểu, nhưng đây là một phương thức hiệu quả hoạt động trong tất cả trình duyệt để đảm bảo rằng mã không quan trọng không chặn khung tiếp theo.

Tránh tình trạng bố cục bị đơ

Sự cố bố cục (đôi khi được gọi là bố cục đồng bộ bắt buộc) là một vấn đề về hiệu suất kết xuất, trong đó bố cục xảy ra đồng bộ. Lỗi này xảy ra khi bạn cập nhật các kiểu trong JavaScript, sau đó đọc các kiểu đó trong cùng một tác vụ. Ngoài ra, có nhiều thuộc tính trong JavaScript có thể gây ra tình trạng bố cục bị lỗi.

Hình ảnh trực quan về tình trạng bố cục bị xáo trộn như trong bảng điều khiển hiệu suất của Công cụ của Chrome cho nhà phát triển.
Ví dụ về tình trạng bố cục bị xáo trộn, như trong bảng hiệu suất của Công cụ của Chrome cho nhà phát triển. Các tác vụ kết xuất liên quan đến tình trạng bố cục bị xáo trộn sẽ được đánh dấu bằng một tam giác màu đỏ ở góc trên bên phải của phần ngăn xếp lệnh gọi, thường được gắn nhãn Recalculate Style (Tính toán lại kiểu) hoặc Layout (Bố cục).

Sự cố bố cục là nút thắt cổ chai về hiệu suất vì khi cập nhật các kiểu rồi yêu cầu ngay các giá trị của các kiểu đó trong JavaScript, trình duyệt buộc phải thực hiện công việc bố cục đồng bộ, nếu không thì có thể đợi để thực hiện không đồng bộ sau khi các lệnh gọi lại sự kiện chạy xong.

Giảm thiểu độ trễ khi trình bày

Độ trễ hiển thị của một điểm đánh dấu tương tác bắt đầu từ thời điểm lệnh gọi lại sự kiện của một lượt tương tác chạy xong, cho đến thời điểm trình duyệt có thể vẽ khung hình tiếp theo cho thấy các thay đổi về hình ảnh.

Giảm thiểu kích thước DOM

Khi DOM của một trang có kích thước nhỏ, công việc kết xuất thường hoàn tất nhanh chóng. Tuy nhiên, khi DOM trở nên rất lớn, công việc kết xuất có xu hướng tăng theo kích thước DOM. Mối quan hệ giữa công việc kết xuất và kích thước DOM không phải là tuyến tính, nhưng DOM lớn đòi hỏi nhiều công việc hơn để kết xuất so với DOM nhỏ. DOM lớn gây ra vấn đề trong hai trường hợp:

  1. Trong quá trình kết xuất trang ban đầu, khi một DOM lớn đòi hỏi nhiều công việc để kết xuất trạng thái ban đầu của trang.
  2. Để phản hồi hoạt động tương tác của người dùng, một DOM lớn có thể khiến quá trình cập nhật kết xuất trở nên rất tốn kém, do đó làm tăng thời gian trình duyệt hiển thị khung tiếp theo.

Xin lưu ý rằng có những trường hợp không thể giảm đáng kể DOM lớn. Mặc dù có một số phương pháp bạn có thể áp dụng để giảm kích thước DOM, chẳng hạn như làm phẳng DOM hoặc thêm vào DOM trong quá trình tương tác của người dùng để giữ cho kích thước DOM ban đầu nhỏ, nhưng những kỹ thuật đó có thể chỉ mang lại hiệu quả ở mức độ nào đó.

Sử dụng content-visibility để hiển thị từng phần các phần tử ngoài màn hình

Một cách để bạn có thể giới hạn cả lượng công việc kết xuất trong quá trình tải trang và lượng công việc kết xuất để phản hồi hoạt động tương tác của người dùng là dựa vào thuộc tính content-visibility CSS. Thuộc tính này giúp kết xuất các phần tử một cách hiệu quả khi chúng tiến đến khung nhìn. Mặc dù bạn có thể phải thực hành một số cách để sử dụng content-visibility một cách hiệu quả, nhưng bạn nên điều tra xem kết quả có thể cải thiện thời gian kết xuất thấp hơn để cải thiện INP của trang hay không.

Hãy lưu ý đến chi phí hiệu suất khi hiển thị HTML bằng JavaScript

Khi có HTML, sẽ có quá trình phân tích cú pháp HTML và sau khi trình duyệt phân tích cú pháp xong HTML thành DOM, trình duyệt phải áp dụng các kiểu cho DOM đó, thực hiện các phép tính bố cục và sau đó hiển thị bố cục đó. Đây là một chi phí không thể tránh khỏi, nhưng cách bạn hiển thị HTML là rất quan trọng.

Khi máy chủ gửi HTML, HTML sẽ đến trình duyệt dưới dạng luồng. Truyền trực tuyến có nghĩa là phản hồi HTML từ máy chủ đang đến theo từng phần. Trình duyệt tối ưu hoá cách xử lý luồng bằng cách phân tích cú pháp từng phần của luồng đó khi chúng đến và hiển thị từng phần. Đây là một phương pháp tối ưu hoá hiệu suất, trong đó trình duyệt tự động và định kỳ trả về kết quả trong quá trình tải trang. Bạn sẽ được hưởng lợi từ phương pháp này mà không mất phí.

Mặc dù lượt truy cập đầu tiên vào bất kỳ trang web nào cũng sẽ luôn liên quan đến một số HTML, nhưng một phương pháp phổ biến là bắt đầu bằng một đoạn HTML ban đầu tối thiểu, sau đó sử dụng JavaScript để điền sẵn khu vực nội dung. Các bản cập nhật tiếp theo cho khu vực nội dung đó cũng xảy ra do hoạt động tương tác của người dùng. Phương thức này thường được gọi là mô hình ứng dụng trang đơn (SPA). Một hạn chế của mẫu này là khi kết xuất HTML bằng JavaScript trên máy khách, bạn không chỉ phải trả chi phí xử lý JavaScript để tạo HTML đó mà trình duyệt cũng sẽ không trả về cho đến khi hoàn tất việc phân tích cú pháp HTML đó và hiển thị HTML đó.

Tuy nhiên, điều quan trọng cần nhớ là ngay cả những trang web không phải là SPA cũng có thể cần hiển thị một số HTML thông qua JavaScript do các hoạt động tương tác. Điều này thường không gây vấn đề, miễn là bạn không hiển thị một lượng lớn HTML trên máy khách, điều này có thể làm chậm việc hiển thị khung hình tiếp theo. Tuy nhiên, bạn cần hiểu rõ những tác động về hiệu suất của phương pháp này đối với việc hiển thị HTML trong trình duyệt và cách phương pháp này có thể ảnh hưởng đến khả năng phản hồi của trang web đối với dữ liệu đầu vào của người dùng nếu bạn đang hiển thị nhiều HTML thông qua JavaScript.

Kết luận

Việc cải thiện INP của trang web là một quá trình lặp lại. Khi khắc phục một lượt tương tác chậm trong trường, rất có thể (đặc biệt nếu trang web của bạn cung cấp nhiều tính năng tương tác) bạn sẽ bắt đầu tìm thấy các lượt tương tác chậm khác và bạn cũng cần tối ưu hoá các lượt tương tác đó.

Mấu chốt để cải thiện INP là tính kiên trì. Theo thời gian, bạn có thể điều chỉnh tính thích ứng của trang để người dùng hài lòng với trải nghiệm mà bạn cung cấp cho họ. Cũng có thể khi phát triển các tính năng mới cho người dùng, bạn cần phải trải qua quy trình tương tự để tối ưu hoá các hoạt động tương tác dành riêng cho họ. Việc này sẽ mất thời gian và công sức, nhưng đó là thời gian và công sức xứng đáng.

Hình ảnh chính trên Unsplash, của David Pisnoy và được sửa đổi theo giấy phép Unsplash.