Tìm các hoạt động tương tác chậm trong trường

Tìm hiểu cách tìm các lượt tương tác chậm trong dữ liệu trường của trang web để có thể tìm cơ hội cải thiện chỉ số Hoạt động tương tác với lần hiển thị tiếp theo.

Dữ liệu thực địa là dữ liệu cho bạn biết cách người dùng thực tế đang trải nghiệm trang web của bạn. Tính năng này giúp bạn phát hiện những vấn đề mà bạn không thể tìm thấy trong dữ liệu phòng thí nghiệm. Đối với chỉ số Lượt tương tác đến lượt vẽ tiếp theo (INP), dữ liệu trường là yếu tố thiết yếu để xác định các lượt tương tác bị chậm và cung cấp các manh mối quan trọng giúp bạn khắc phục vấn đề.

Trong hướng dẫn này, bạn sẽ tìm hiểu cách nhanh chóng đánh giá INP của trang web bằng dữ liệu thực tế từ Báo cáo trải nghiệm người dùng trên Chrome (CrUX) để xem trang web của bạn có gặp vấn đề về INP hay không. Tiếp theo, bạn sẽ tìm hiểu cách sử dụng bản dựng phân bổ của thư viện JavaScript web-vitals và thông tin chi tiết mới mà thư viện này cung cấp từ Long Animation Frames API (LoAF) để thu thập và diễn giải dữ liệu trường cho các lượt tương tác chậm trên trang web của bạn.

Bắt đầu với CrUX để đánh giá INP của trang web

Nếu bạn không thu thập dữ liệu thực tế tại trang từ người dùng trang web, thì CrUX có thể là một điểm khởi đầu phù hợp. CrUX thu thập dữ liệu thực tế từ những người dùng Chrome thực sự đã chọn gửi dữ liệu đo từ xa.

Dữ liệu CrUX xuất hiện ở một số khu vực khác nhau và tuỳ thuộc vào phạm vi thông tin mà bạn đang tìm kiếm. CrUX có thể cung cấp dữ liệu về INP và các chỉ số quan trọng khác của Core Web Vitals cho:

  • Các trang riêng lẻ và toàn bộ nguồn gốc bằng PageSpeed Insights.
  • Loại trang. Ví dụ: nhiều trang web thương mại điện tử có các loại Trang chi tiết sản phẩm và Trang thông tin sản phẩm. Bạn có thể xem dữ liệu CrUX cho các loại trang riêng biệt trong Search Console.

Để bắt đầu, bạn có thể nhập URL của trang web vào PageSpeed Insights. Sau khi bạn nhập URL, dữ liệu trường cho URL đó (nếu có) sẽ xuất hiện cho nhiều chỉ số, bao gồm cả INP. Bạn cũng có thể sử dụng nút bật/tắt để kiểm tra các giá trị INP cho phương diện thiết bị di động và máy tính.

Dữ liệu thực tế do CrUX cung cấp trong PageSpeed Insights, cho thấy LCP, INP, CLS ở 3 chỉ số quan trọng chính của trang web, TTFB, FCP dưới dạng chỉ số chẩn đoán và FID dưới dạng chỉ số quan trọng chính của trang web không còn được dùng nữa.
Thông tin đọc dữ liệu CrUX như trong PageSpeed Insights. Trong ví dụ này, INP của trang web nhất định cần được cải thiện.

Dữ liệu này rất hữu ích vì cho bạn biết liệu bạn có gặp vấn đề gì không. Tuy nhiên, CrUX không thể cho bạn biết điều gì đang gây ra sự cố. Có nhiều giải pháp Giám sát người dùng thực (RUM) có thể giúp bạn thu thập dữ liệu trường của riêng mình từ người dùng trang web để trả lời câu hỏi đó. Một lựa chọn là tự thu thập dữ liệu trường đó bằng cách sử dụng thư viện JavaScript web-vitals.

Thu thập dữ liệu thực địa bằng thư viện JavaScript web-vitals

Thư viện JavaScript web-vitals là một tập lệnh mà bạn có thể tải trên trang web của mình để thu thập dữ liệu trường từ người dùng trang web. Bạn có thể sử dụng tính năng này để ghi lại một số chỉ số, bao gồm cả INP trong các trình duyệt hỗ trợ tính năng này.

Hỗ trợ trình duyệt

  • Chrome: 96.
  • Edge: 96.
  • Firefox: không được hỗ trợ.
  • Safari: không được hỗ trợ.

Nguồn

Bạn có thể sử dụng bản dựng chuẩn của thư viện web-vitals để lấy dữ liệu INP cơ bản từ người dùng trong trường hợp thực tế:

import {onINP} from 'web-vitals';

onINP
(({name, value, rating}) => {
  console
.log(name);    // 'INP'
  console
.log(value);   // 512
  console
.log(rating);  // 'poor'
});

Để phân tích dữ liệu trường từ người dùng, bạn cần gửi dữ liệu này đến một nơi nào đó:

import {onINP} from 'web-vitals';

onINP
(({name, value, rating}) => {
 
// Prepare JSON to be sent for collection. Note that
 
// you can add anything else you'd want to collect here:
 
const body = JSON.stringify({name, value, rating});

 
// Use `sendBeacon` to send data to an analytics endpoint.
 
// For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
  navigator
.sendBeacon('/analytics', body);
});

Tuy nhiên, dữ liệu này không cho bạn biết nhiều thông tin hơn so với CrUX. Đó là lúc bạn cần đến bản dựng phân bổ của thư viện web-vitals.

Khám phá thêm với bản dựng phân bổ của thư viện web-vitals

Bản dựng phân bổ của thư viện web-vitals hiển thị dữ liệu bổ sung mà bạn có thể nhận được từ người dùng trong thực tế để giúp bạn khắc phục hiệu quả hơn các lượt tương tác có vấn đề đang ảnh hưởng đến INP của trang web. Bạn có thể truy cập dữ liệu này thông qua đối tượng attribution xuất hiện trong phương thức onINP() của thư viện:

import {onINP} from 'web-vitals/attribution';

onINP
(({name, value, rating, attribution}) => {
  console
.log(name);         // 'INP'
  console
.log(value);        // 56
  console
.log(rating);       // 'good'
  console
.log(attribution);  // Attribution data object
});
Cách nhật ký bảng điều khiển từ thư viện web-vitals xuất hiện. Bảng điều khiển trong ví dụ này cho thấy tên của chỉ số (INP), giá trị INP (56), trong đó giá trị đó nằm trong ngưỡng INP (tốt) và nhiều thông tin khác nhau xuất hiện trong đối tượng phân bổ, bao gồm cả các mục nhập từ API Khung ảnh động dài.
Cách dữ liệu từ thư viện web-vitals xuất hiện trong bảng điều khiển.

Ngoài chính INP của trang, bản dựng phân bổ còn cung cấp nhiều dữ liệu mà bạn có thể sử dụng để hiểu lý do khiến lượt tương tác bị chậm, bao gồm cả phần tương tác mà bạn nên tập trung vào. Báo cáo này có thể giúp bạn trả lời các câu hỏi quan trọng như:

  • "Người dùng có tương tác với trang trong khi trang đang tải không?"
  • "Trình xử lý sự kiện của hoạt động tương tác có chạy trong thời gian dài không?"
  • "Mã trình xử lý sự kiện tương tác có bị trì hoãn khi bắt đầu không? Nếu có, thì tại thời điểm đó, luồng chính còn xảy ra điều gì khác?"
  • "Hoạt động tương tác có gây ra nhiều công việc kết xuất khiến khung hình tiếp theo bị trì hoãn không?"

Bảng sau đây cho thấy một số dữ liệu phân bổ cơ bản mà bạn có thể nhận được từ thư viện. Dữ liệu này có thể giúp bạn tìm hiểu một số nguyên nhân chính khiến lượt tương tác trên trang web bị chậm:

Khoá đối tượng attribution Dữ liệu
interactionTarget Bộ chọn CSS trỏ đến phần tử đã tạo ra giá trị INP của trang, ví dụ: button#save.
interactionType Loại tương tác, từ lượt nhấp, lượt nhấn hoặc dữ liệu đầu vào từ bàn phím.
inputDelay* Độ trễ đầu vào của lượt tương tác.
processingDuration* Khoảng thời gian từ khi trình nghe sự kiện đầu tiên bắt đầu chạy để phản hồi hoạt động tương tác của người dùng cho đến khi tất cả các trình xử lý sự kiện đã hoàn tất.
presentationDelay* Độ trễ hiển thị của hoạt động tương tác, bắt đầu từ thời điểm trình xử lý sự kiện kết thúc cho đến thời điểm khung hình tiếp theo được vẽ.
longAnimationFrameEntries* Các mục nhập từ LoAF liên kết với lượt tương tác. Hãy xem phần tiếp theo để biết thêm thông tin.
*Mới trong phiên bản 4

Kể từ phiên bản 4 của thư viện web-vitals, bạn có thể hiểu rõ hơn về các lượt tương tác có vấn đề thông qua dữ liệu mà thư viện này cung cấp với bảng chi tiết về giai đoạn INP (độ trễ đầu vào, thời lượng xử lý và độ trễ hiển thị) và API Khung ảnh động dài (LoAF).

API Khung ảnh động dài (LoAF)

Hỗ trợ trình duyệt

  • Chrome: 123.
  • Edge: 123.
  • Firefox: không được hỗ trợ.
  • Safari: không được hỗ trợ.

Nguồn

Gỡ lỗi tương tác bằng dữ liệu trường là một nhiệm vụ đầy thách thức. Tuy nhiên, với dữ liệu từ LoAF, giờ đây, bạn có thể hiểu rõ hơn về nguyên nhân gây ra tình trạng tương tác chậm, vì LoAF cho thấy một số thời gian chi tiết và dữ liệu khác mà bạn có thể sử dụng để xác định chính xác nguyên nhân, và quan trọng hơn là vị trí nguồn gốc của sự cố trong mã trang web.

Bản dựng phân bổ của thư viện web-vitals hiển thị một mảng các mục nhập LoAF trong khoá longAnimationFrameEntries của đối tượng attribution. Bảng sau đây liệt kê một số dữ liệu chính mà bạn có thể tìm thấy trong mỗi mục nhập LoAF:

Khoá đối tượng mục nhập LoAF Dữ liệu
duration Thời lượng của khung ảnh động dài, cho đến khi bố cục hoàn tất, nhưng không bao gồm việc vẽ và kết hợp.
blockingDuration Tổng thời gian trong khung mà trình duyệt không thể phản hồi nhanh do các tác vụ kéo dài. Thời gian chặn này có thể bao gồm các tác vụ dài chạy JavaScript, cũng như mọi tác vụ kết xuất dài tiếp theo trong khung.
firstUIEventTimestamp Dấu thời gian của thời điểm sự kiện được đưa vào hàng đợi trong khung. Hữu ích khi tìm hiểu thời điểm bắt đầu độ trễ đầu vào của một lượt tương tác.
startTime Dấu thời gian bắt đầu của khung hình.
renderStart Thời điểm bắt đầu công việc kết xuất cho khung hình. Điều này bao gồm mọi lệnh gọi lại requestAnimationFrame (và lệnh gọi lại ResizeObserver nếu có), nhưng có thể xảy ra trước khi bất kỳ công việc nào về kiểu/bố cục bắt đầu.
styleAndLayoutStart Khi hoạt động kiểu/bố cục trong khung xảy ra. Có thể hữu ích trong việc xác định thời lượng của công việc về kiểu/bố cục khi tính đến các dấu thời gian có sẵn khác.
scripts Một mảng các mục chứa thông tin phân bổ tập lệnh đóng góp vào INP của trang.
Hình ảnh trực quan của một khung ảnh động dài theo mô hình LoAF.
Sơ đồ về thời gian của một khung ảnh động dài theo API LoAF (trừ blockingDuration).

Tất cả thông tin này có thể cho bạn biết nhiều điều về nguyên nhân khiến lượt tương tác bị chậm, nhưng mảng scripts mà các mục nhập LoAF hiển thị sẽ đặc biệt quan tâm:

Khoá đối tượng phân bổ tập lệnh Dữ liệu
invoker Phương thức gọi. Điều này có thể thay đổi tuỳ theo loại phương thức gọi được mô tả trong hàng tiếp theo. Ví dụ về phương thức gọi có thể là các giá trị như 'IMG#id.onload', 'Window.requestAnimationFrame' hoặc 'Response.json.then'.
invokerType Loại phương thức gọi. Có thể là 'user-callback', 'event-listener', 'resolve-promise', 'reject-promise', 'classic-script' hoặc 'module-script'.
sourceURL URL của tập lệnh nơi bắt nguồn khung ảnh động cần nhiều thời gian.
sourceCharPosition Vị trí ký tự trong tập lệnh được xác định bằng sourceURL.
sourceFunctionName Tên của hàm trong tập lệnh đã xác định.

Mỗi mục trong mảng này chứa dữ liệu hiển thị trong bảng này, cung cấp cho bạn thông tin về tập lệnh chịu trách nhiệm cho việc tương tác chậm và mức độ chịu trách nhiệm của tập lệnh đó.

Đo lường và xác định các nguyên nhân phổ biến gây ra tình trạng tương tác chậm

Để giúp bạn biết cách sử dụng thông tin này, hướng dẫn này sẽ hướng dẫn bạn cách sử dụng dữ liệu LoAF xuất hiện trong thư viện web-vitals để xác định một số nguyên nhân gây ra tình trạng tương tác chậm.

Thời gian xử lý lâu

Thời lượng xử lý của một lượt tương tác là thời gian cần thiết để các lệnh gọi lại trình xử lý sự kiện đã đăng ký của lượt tương tác chạy xong và mọi thứ khác có thể xảy ra trong khoảng thời gian đó. Thư viện web-vitals hiển thị thời lượng xử lý cao:

import {onINP} from 'web-vitals/attribution';

onINP
(({name, value, attribution}) => {
 
const {processingDuration} = attribution; // 512.5
});

Bạn có thể nghĩ rằng nguyên nhân chính dẫn đến việc tương tác chậm là do mã trình xử lý sự kiện của bạn mất quá nhiều thời gian để chạy, nhưng điều này không phải lúc nào cũng đúng! Sau khi xác nhận rằng đây là vấn đề, bạn có thể tìm hiểu sâu hơn bằng dữ liệu LoAF:

import {onINP} from 'web-vitals/attribution';

onINP
(({name, value, attribution}) => {
 
const {processingDuration} = attribution; // 512.5

 
// Get the longest script from LoAF covering `processingDuration`:
 
const loaf = attribution.longAnimationFrameEntries.at(-1);
 
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];

 
if (script) {
   
// Get attribution for the long-running event handler:
   
const {invokerType} = script;        // 'event-listener'
   
const {invoker} = script;            // 'BUTTON#update.onclick'
   
const {sourceURL} = script;          // 'https://example.com/app.js'
   
const {sourceCharPosition} = script; // 83
   
const {sourceFunctionName} = script; // 'update'
 
}
});

Như bạn có thể thấy trong đoạn mã trước, bạn có thể xử lý dữ liệu LoAF để tìm ra nguyên nhân chính xác đằng sau một lượt tương tác có giá trị thời lượng xử lý cao, bao gồm:

  • Phần tử và trình nghe sự kiện đã đăng ký của phần tử đó.
  • Tệp tập lệnh và vị trí ký tự trong tệp đó chứa mã trình xử lý sự kiện chạy trong thời gian dài.
  • Tên của hàm.

Loại dữ liệu này rất có giá trị. Bạn không cần phải tự tìm hiểu xem chính xác hoạt động tương tác nào hoặc trình xử lý sự kiện nào chịu trách nhiệm về các giá trị thời lượng xử lý cao nữa. Ngoài ra, vì các tập lệnh của bên thứ ba thường có thể đăng ký trình xử lý sự kiện của riêng mình, nên bạn có thể xác định xem mã của mình có phải là nguyên nhân hay không! Đối với mã mà bạn có quyền kiểm soát, bạn nên tìm hiểu cách tối ưu hoá các tác vụ dài.

Độ trễ đầu vào dài

Mặc dù trình xử lý sự kiện chạy trong thời gian dài là phổ biến, nhưng bạn cũng cần xem xét các phần khác của hoạt động tương tác. Một phần xảy ra trước khoảng thời gian xử lý, được gọi là độ trễ đầu vào. Đây là khoảng thời gian từ khi người dùng bắt đầu tương tác cho đến thời điểm lệnh gọi lại trình xử lý sự kiện bắt đầu chạy và xảy ra khi luồng chính đang xử lý một tác vụ khác. Bản dựng phân bổ của thư viện web-vitals có thể cho bạn biết thời lượng độ trễ đầu vào cho một lượt tương tác:

import {onINP} from 'web-vitals/attribution';

onINP
(({name, value, attribution}) => {
 
const {inputDelay} = attribution; // 125.59439536
});

Nếu nhận thấy một số lượt tương tác có độ trễ đầu vào cao, thì bạn cần tìm hiểu xem điều gì đang xảy ra trên trang tại thời điểm tương tác gây ra độ trễ đầu vào lâu. Điều này thường tóm gọn là liệu lượt tương tác có xảy ra khi trang đang tải hay sau đó.

Lỗi xảy ra trong khi tải trang không?

Luồng chính thường bận nhất khi một trang đang tải. Trong thời gian này, tất cả các loại tác vụ đều đang được đưa vào hàng đợi và xử lý. Nếu người dùng cố gắng tương tác với trang trong khi tất cả công việc này đang diễn ra, thì việc tương tác có thể bị trì hoãn. Các trang tải nhiều JavaScript có thể bắt đầu công việc biên dịch và đánh giá tập lệnh, cũng như thực thi các hàm giúp trang sẵn sàng cho các hoạt động tương tác của người dùng. Công việc này có thể gây trở ngại nếu người dùng tình cờ tương tác khi hoạt động này diễn ra. Bạn có thể tìm hiểu xem liệu người dùng trang web của mình có gặp phải trường hợp đó hay không:

import {onINP} from 'web-vitals/attribution';

onINP
(({name, value, attribution}) => {
 
const {inputDelay} = attribution; // 125.59439536

 
// Get the longest script from the first LoAF entry:
 
const loaf = attribution.longAnimationFrameEntries[0];
 
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];

 
if (script) {
   
// Invoker types can describe if script eval blocked the main thread:
   
const {invokerType} = script;    // 'classic-script' | 'module-script'
   
const {sourceLocation} = script; // 'https://example.com/app.js'
 
}
});

Nếu bạn ghi lại dữ liệu này trong trường và thấy độ trễ đầu vào cao và các loại trình gọi là 'classic-script' hoặc 'module-script', thì có thể nói rằng các tập lệnh trên trang web của bạn đang mất nhiều thời gian để đánh giá và đang chặn luồng chính đủ lâu để trì hoãn các lượt tương tác. Bạn có thể giảm thời gian chặn này bằng cách chia các tập lệnh thành các gói nhỏ hơn, trì hoãn việc tải mã không dùng đến ban đầu vào lúc khác và kiểm tra trang web của bạn để tìm mã không dùng đến mà bạn có thể xoá hoàn toàn.

Có phải sau khi tải trang không?

Mặc dù độ trễ đầu vào thường xảy ra trong khi trang đang tải, nhưng cũng có thể xảy ra sau khi trang đã tải xong, do một nguyên nhân hoàn toàn khác. Các nguyên nhân phổ biến gây ra độ trễ đầu vào sau khi tải trang có thể là mã chạy định kỳ do lệnh gọi setInterval trước đó hoặc thậm chí là lệnh gọi lại sự kiện đã được đưa vào hàng đợi để chạy trước đó và vẫn đang xử lý.

import {onINP} from 'web-vitals/attribution';

onINP
(({name, value, attribution}) => {
 
const {inputDelay} = attribution; // 125.59439536

 
// Get the longest script from the first LoAF entry:
 
const loaf = attribution.longAnimationFrameEntries[0];
 
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];

 
if (script) {
   
const {invokerType} = script;        // 'user-callback'
   
const {sourceURL} = script;          // 'https://example.com/app.js'
   
const {sourceCharPosition} = script; // 83
   
const {sourceFunctionName} = script; // 'update'
 
}
});

Giống như trường hợp khắc phục sự cố về giá trị thời lượng xử lý cao, độ trễ đầu vào cao do các nguyên nhân được đề cập trước đó sẽ cung cấp cho bạn dữ liệu phân bổ tập lệnh chi tiết. Tuy nhiên, điểm khác biệt là loại phương thức gọi sẽ thay đổi dựa trên bản chất của công việc đã trì hoãn hoạt động tương tác:

  • 'user-callback' cho biết tác vụ chặn là từ setInterval, setTimeout hoặc thậm chí là requestAnimationFrame.
  • 'event-listener' cho biết tác vụ chặn là từ một đầu vào trước đó đã được đưa vào hàng đợi và vẫn đang xử lý.
  • 'resolve-promise''reject-promise' có nghĩa là tác vụ chặn là từ một số công việc không đồng bộ đã bắt đầu trước đó và được giải quyết hoặc bị từ chối tại thời điểm người dùng cố gắng tương tác với trang, làm chậm quá trình tương tác.

Trong mọi trường hợp, dữ liệu phân bổ tập lệnh sẽ cho bạn biết nên bắt đầu tìm ở đâu và liệu độ trễ đầu vào có phải là do mã của riêng bạn hay của tập lệnh bên thứ ba.

Độ trễ khi trình bày lâu

Độ trễ hiển thị là chặng cuối của một lượt tương tác và bắt đầu khi trình xử lý sự kiện của lượt tương tác kết thúc, cho đến thời điểm khung hình tiếp theo được vẽ. Các sự kiện này xảy ra khi công việc trong trình xử lý sự kiện do một hoạt động tương tác thay đổi trạng thái hình ảnh của giao diện người dùng. Cũng như thời lượng xử lý và độ trễ đầu vào, thư viện web-vitals có thể cho bạn biết độ trễ hiển thị của một lượt tương tác:

import {onINP} from 'web-vitals/attribution';

onINP
(({name, value, attribution}) => {
 
const {presentationDelay} = attribution; // 113.32307691
});

Nếu bạn ghi lại dữ liệu này và thấy độ trễ hiển thị cao đối với các lượt tương tác đóng góp vào INP của trang web, thì nguyên nhân có thể khác nhau, nhưng sau đây là một số nguyên nhân cần chú ý.

Chi phí cao cho việc thiết kế bố cục và kiểu

Việc trình bày bị trễ lâu có thể là do tính toán lại kiểubố cục tốn kém, xuất phát từ một số nguyên nhân, bao gồm cả bộ chọn CSS phức tạp và kích thước DOM lớn. Bạn có thể đo lường thời lượng của công việc này bằng thời gian LoAF xuất hiện trong thư viện web-vitals:

import {onINP} from 'web-vitals/attribution';

onINP
(({name, value, attribution}) => {
 
const {presentationDelay} = attribution; // 113.32307691

 
// Get the longest script from the last LoAF entry:
 
const loaf = attribution.longAnimationFrameEntries.at(-1);
 
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];

 
// Get necessary timings:
 
const {startTime} = loaf; // 2120.5
 
const {duration} = loaf;  // 1002

 
// Figure out the ending timestamp of the frame (approximate):
 
const endTime = startTime + duration; // 3122.5

 
// Get the start timestamp of the frame's style/layout work:
 
const {styleAndLayoutStart} = loaf; // 3011.17692309

 
// Calculate the total style/layout duration:
 
const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691

 
if (script) {
   
// Get attribution for the event handler that triggered
   
// the long-running style and layout operation:
   
const {invokerType} = script;        // 'event-listener'
   
const {invoker} = script;            // 'BUTTON#update.onclick'
   
const {sourceURL} = script;          // 'https://example.com/app.js'
   
const {sourceCharPosition} = script; // 83
   
const {sourceFunctionName} = script; // 'update'
 
}
});

LoAF sẽ không cho bạn biết thời lượng của công việc về kiểu và bố cục cho một khung, nhưng sẽ cho bạn biết thời điểm bắt đầu công việc đó. Với dấu thời gian bắt đầu này, bạn có thể sử dụng dữ liệu khác từ LoAF để tính toán thời lượng chính xác của công việc đó bằng cách xác định thời gian kết thúc của khung và trừ dấu thời gian bắt đầu của công việc về kiểu và bố cục khỏi thời lượng đó.

Lệnh gọi lại requestAnimationFrame chạy trong thời gian dài

Một nguyên nhân tiềm ẩn gây ra tình trạng trễ bản trình bày lâu là do quá nhiều công việc được thực hiện trong lệnh gọi lại requestAnimationFrame. Nội dung của lệnh gọi lại này được thực thi sau khi trình xử lý sự kiện chạy xong, nhưng ngay trước khi tính toán lại kiểu và bố cục.

Các lệnh gọi lại này có thể mất nhiều thời gian để hoàn tất nếu công việc được thực hiện trong đó phức tạp. Nếu nghi ngờ các giá trị độ trễ hiển thị cao là do công việc bạn đang thực hiện với requestAnimationFrame, bạn có thể sử dụng dữ liệu LoAF do thư viện web-vitals hiển thị để xác định những trường hợp sau:

onINP(({name, value, attribution}) => {
 
const {presentationDelay} = attribution; // 543.1999999880791

 
// Get the longest script from the last LoAF entry:
 
const loaf = attribution.longAnimationFrameEntries.at(-1);
 
const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];

 
// Get the render start time and when style and layout began:
 
const {renderStart} = loaf;         // 2489
 
const {styleAndLayoutStart} = loaf; // 2989.5999999940395

 
// Calculate the `requestAnimationFrame` callback's duration:
 
const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954

 
if (script) {
   
// Get attribution for the event handler that triggered
   
// the long-running requestAnimationFrame callback:
   
const {invokerType} = script;        // 'user-callback'
   
const {invoker} = script;            // 'FrameRequestCallback'
   
const {sourceURL} = script;          // 'https://example.com/app.js'
   
const {sourceCharPosition} = script; // 83
   
const {sourceFunctionName} = script; // 'update'
 
}
});

Nếu bạn thấy rằng một phần đáng kể thời gian trễ của bản trình bày được dành cho lệnh gọi lại requestAnimationFrame, hãy đảm bảo rằng công việc bạn đang thực hiện trong các lệnh gọi lại này chỉ giới hạn ở việc thực hiện công việc dẫn đến việc cập nhật thực tế cho giao diện người dùng. Mọi công việc khác không liên quan đến DOM hoặc cập nhật kiểu sẽ làm chậm khung hình tiếp theo một cách không cần thiết, vì vậy, hãy cẩn thận!

Kết luận

Dữ liệu thực địa là nguồn thông tin tốt nhất mà bạn có thể tham khảo khi tìm hiểu những hoạt động tương tác nào gây ra vấn đề cho người dùng thực tế trong thực địa. Bằng cách dựa vào các công cụ thu thập dữ liệu thực địa như thư viện JavaScript web-vitals (hoặc nhà cung cấp RUM), bạn có thể tự tin hơn về những lượt tương tác gặp vấn đề nhiều nhất, sau đó chuyển sang tái tạo các lượt tương tác gặp vấn đề trong phòng thí nghiệm rồi tiến hành khắc phục.

Hình ảnh chính trên Unsplash, của Federico Respini.