Hiệu suất gỡ lỗi trong trường

Tìm hiểu cách phân bổ dữ liệu hiệu suất bằng thông tin gỡ lỗi để giúp bạn xác định và khắc phục các vấn đề của người dùng thực thông qua số liệu phân tích

Google cung cấp hai danh mục công cụ để đo lường và gỡ lỗi hiệu suất:

  • Công cụ phòng thí nghiệm: Các công cụ như Lighthouse, trong đó trang của bạn được tải trong một môi trường mô phỏng có thể bắt chước nhiều điều kiện (ví dụ: mạng chậm và thiết bị di động cấp thấp).
  • Công cụ thực địa: Các công cụ như Báo cáo trải nghiệm người dùng trên Chrome (CrUX) dựa trên dữ liệu tổng hợp của người dùng thực từ Chrome. (Xin lưu ý rằng dữ liệu thực trường do các công cụ như PageSpeed InsightsSearch Console báo cáo, lấy nguồn từ dữ liệu CrUX.)

Mặc dù công cụ thực địa cung cấp dữ liệu chính xác hơn (dữ liệu thực sự thể hiện trải nghiệm thực tế của người dùng), nhưng các công cụ trong phòng thí nghiệm thường giúp bạn xác định và khắc phục vấn đề hiệu quả hơn.

Dữ liệu CrUX thể hiện chính xác hơn hiệu suất thực tế của trang. Tuy nhiên, việc biết được điểm CrUX chưa chắc sẽ giúp bạn tìm ra cách cải thiện hiệu suất.

Mặt khác, Lighthouse sẽ xác định các vấn đề và đưa ra các đề xuất cụ thể về cách cải thiện. Tuy nhiên, Lighthouse sẽ chỉ đưa ra đề xuất cho các vấn đề về hiệu suất mà Lighthouse phát hiện thấy tại thời gian tải trang. Tính năng này không phát hiện các vấn đề chỉ xuất hiện do hoạt động tương tác của người dùng, chẳng hạn như cuộn hoặc nhấp vào các nút trên trang.

Việc này đặt ra một câu hỏi quan trọng: làm thế nào để có thể thu thập thông tin gỡ lỗi cho Các chỉ số quan trọng về trang web hoặc các chỉ số hiệu suất khác từ người dùng thực trong thực tế?

Bài đăng này sẽ giải thích chi tiết những API mà bạn có thể sử dụng để thu thập thêm thông tin gỡ lỗi cho từng chỉ số Chỉ số quan trọng chính của trang web hiện tại, đồng thời cung cấp cho bạn ý tưởng về cách thu thập dữ liệu này trong công cụ phân tích hiện có của bạn.

API để phân bổ và gỡ lỗi

CLS (Mức thay đổi bố cục tích luỹ)

Trong tất cả chỉ số Các chỉ số quan trọng về trang web, CLS có lẽ là chỉ số quan trọng nhất đối với việc thu thập thông tin gỡ lỗi trong trường. CLS (Điểm số tổng hợp về mức thay đổi bố cục) được đo lường trong toàn bộ thời gian hoạt động của trang. Vì vậy, cách người dùng tương tác với trang (khoảng thời gian họ cuộn, nội dung họ nhấp vào, v.v.) có thể có tác động đáng kể đến việc liệu bố cục có thay đổi hay không và những phần tử nào đang thay đổi.

Hãy cân nhắc báo cáo sau đây của PageSpeed Insights:

Báo cáo PageSpeed Insights với các giá trị CLS (Điểm số tổng hợp về mức thay đổi bố cục)

Giá trị được báo cáo cho CLS từ phòng thí nghiệm (Lighthouse) so với CLS từ trường (dữ liệu CrUX) khá khác nhau. Điều này hợp lý nếu bạn cho rằng trang có thể có nhiều nội dung tương tác không được dùng khi kiểm thử trong Lighthouse.

Nhưng ngay cả khi hiểu rằng hoạt động tương tác của người dùng ảnh hưởng đến dữ liệu trường, bạn vẫn cần biết phần tử nào trên trang đang dịch chuyển để dẫn đến điểm là 0,3 ở phân vị thứ 75.

Nhờ giao diện LayoutShiftAttribution, bạn có thể thực hiện điều đó.

Nhận mô hình phân bổ thay đổi bố cục

Giao diện LayoutShiftAttribution hiển thị trên mỗi mục nhập layout-shiftAPI không ổn định bố cục phát ra.

Để biết nội dung giải thích chi tiết về cả hai giao diện này, hãy xem bài viết Gỡ lỗi về thay đổi bố cục. Nhằm mục đích của bài đăng này, điều chính bạn cần biết là với tư cách là nhà phát triển, bạn có thể quan sát mọi lần thay đổi bố cục xảy ra trên trang cũng như những phần tử đang thay đổi.

Dưới đây là một số mã ví dụ ghi lại từng lần thay đổi bố cục cũng như các phần tử đã thay đổi:

new PerformanceObserver((list) => {
  for (const {value, startTime, sources} of list.getEntries()) {
    // Log the shift amount and other entry info.
    console.log('Layout shift:', {value, startTime});
    if (sources) {
      for (const {node, curRect, prevRect} of sources) {
        // Log the elements that shifted.
        console.log('  Shift source:', node, {curRect, prevRect});
      }
    }
  }
}).observe({type: 'layout-shift', buffered: true});

Có thể bạn sẽ không thể đo lường và gửi dữ liệu đến công cụ phân tích của mình cho mọi lần thay đổi bố cục xảy ra; tuy nhiên, bằng cách theo dõi tất cả các thay đổi, bạn có thể theo dõi các thay đổi xấu nhất và chỉ báo cáo thông tin về các thay đổi đó.

Mục tiêu không phải là xác định và khắc phục mọi thay đổi về bố cục xảy ra cho mọi người dùng; mục tiêu là xác định những thay đổi ảnh hưởng đến nhiều người dùng nhất, và từ đó đóng góp nhiều nhất vào CLS (Điểm số tổng hợp về mức thay đổi bố cục) của trang ở phân vị thứ 75.

Ngoài ra, bạn không cần tính toán phần tử nguồn lớn nhất mỗi khi có sự thay đổi, mà chỉ cần làm khi đã sẵn sàng gửi giá trị CLS đến công cụ phân tích.

Đoạn mã sau đây lấy danh sách các mục layout-shift đã đóng góp vào CLS và trả về phần tử nguồn lớn nhất từ lần thay đổi lớn nhất:

function getCLSDebugTarget(entries) {
  const largestEntry = entries.reduce((a, b) => {
    return a && a.value > b.value ? a : b;
  });
  if (largestEntry && largestEntry.sources && largestEntry.sources.length) {
    const largestSource = largestEntry.sources.reduce((a, b) => {
      return a.node && a.previousRect.width * a.previousRect.height >
          b.previousRect.width * b.previousRect.height ? a : b;
    });
    if (largestSource) {
      return largestSource.node;
    }
  }
}

Sau khi xác định được yếu tố lớn nhất góp phần vào sự thay đổi lớn nhất, bạn có thể báo cáo điều đó cho công cụ phân tích.

Phần tử đóng góp nhiều nhất vào CLS cho một trang nhất định có thể sẽ thay đổi tuỳ theo người dùng. Tuy nhiên, nếu tổng hợp các yếu tố đó trên tất cả người dùng, bạn sẽ có thể tạo danh sách các phần tử thay đổi ảnh hưởng đến nhiều người dùng nhất.

Sau khi bạn đã xác định và khắc phục nguyên nhân gốc của sự thay đổi đối với các thành phần đó, mã phân tích sẽ bắt đầu báo cáo các thay đổi nhỏ hơn khi có sự thay đổi "kém nhất" trên các trang của bạn. Cuối cùng, tất cả thay đổi được báo cáo sẽ đủ nhỏ để các trang của bạn ở trong ngưỡng "tốt" là 0,1!

Một số siêu dữ liệu khác có thể hữu ích khi thu thập cùng với phần tử nguồn thay đổi lớn nhất là:

  • Thời gian có sự biến động lớn nhất
  • Đường dẫn URL tại thời điểm diễn ra thay đổi lớn nhất (đối với các trang web cập nhật URL động, chẳng hạn như Ứng dụng trang đơn).

LCP (Thời gian hiển thị nội dung lớn nhất)

Để gỡ lỗi LCP trong trường này, thông tin chính bạn cần là phần tử cụ thể lớn nhất (phần tử đề xuất LCP) cho lượt tải trang cụ thể đó.

Xin lưu ý rằng hoàn toàn có thể xảy ra — trên thực tế, khá phổ biến — phần tử đề xuất LCP sẽ khác nhau giữa người dùng với người dùng, ngay cả đối với cùng một trang.

Điều này có thể xảy ra vì một vài lý do:

  • Thiết bị người dùng có độ phân giải màn hình khác nhau, dẫn đến bố cục trang khác nhau và do đó các phần tử khác nhau hiển thị trong khung nhìn.
  • Không phải lúc nào người dùng cũng tải các trang cuộn lên trên cùng. Thông thường, đường liên kết sẽ chứa giá trị nhận dạng theo mảnh hoặc thậm chí là mảnh văn bản. Điều này có nghĩa là các trang của bạn có thể được tải và hiển thị ở bất kỳ vị trí cuộn nào trên trang.
  • Nội dung có thể được cá nhân hoá cho người dùng hiện tại, do đó, thành phần đề xuất LCP có thể thay đổi rất nhiều tuỳ theo người dùng.

Điều này có nghĩa là bạn không thể đưa ra giả định về việc phần tử hoặc tập hợp phần tử nào sẽ là phần tử ứng viên LCP phổ biến nhất cho một trang cụ thể. Bạn phải đo lường chỉ số đó dựa trên hành vi thực của người dùng.

Xác định thành phần ứng viên LCP

Để xác định phần tử đề xuất LCP trong JavaScript, bạn có thể sử dụng API Nội dung lớn nhất hiển thị, chính là API mà bạn dùng để xác định giá trị thời gian LCP.

Khi quan sát các mục nhập largest-contentful-paint, bạn có thể xác định phần tử đề xuất LCP hiện tại bằng cách xem thuộc tính element của mục nhập gần đây nhất:

new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lastEntry = entries[entries.length - 1];

  console.log('LCP element:', lastEntry.element);
}).observe({type: 'largest-contentful-paint', buffered: true});

Sau khi biết phần tử ứng cử viên LCP, bạn có thể gửi phần tử đó đến công cụ phân tích cùng với giá trị chỉ số. Giống như CLS, bảng này sẽ giúp bạn xác định những thành phần quan trọng nhất cần tối ưu hoá trước tiên.

Ngoài phần tử đề xuất LCP, bạn cũng nên đo lường thời gian phụ của LCP. Thông tin này có thể hữu ích khi xác định những bước tối ưu hoá cụ thể có liên quan đến trang web của bạn.

FID (Thời gian phản hồi lần tương tác đầu tiên)

Để gỡ lỗi FID trong trường, điều quan trọng cần nhớ là FID chỉ đo lường phần độ trễ của độ trễ tổng thể của sự kiện đầu vào đầu tiên. Điều đó có nghĩa là những gì người dùng tương tác không thực sự quan trọng bằng những gì khác đang diễn ra trên luồng chính tại thời điểm họ tương tác.

Ví dụ: nhiều ứng dụng JavaScript hỗ trợ tính năng hiển thị phía máy chủ (SSR) sẽ phân phối HTML tĩnh có thể kết xuất lên màn hình trước khi tương tác với hoạt động đầu vào của người dùng, tức là trước khi JavaScript cần thiết để nội dung tương tác tải xong.

Đối với những loại ứng dụng này, bạn cần phải biết liệu hoạt động đầu vào đầu tiên xảy ra trước hay sau khi hydrat hoá. Nếu thực tế cho thấy có nhiều người đang cố gắng tương tác với trang trước khi quá trình hiển thị nước hoàn tất, hãy cân nhắc hiển thị các trang của bạn ở trạng thái vô hiệu hoá hoặc đang tải thay vì ở trạng thái tương tác.

Nếu khung ứng dụng hiển thị dấu thời gian hydrat hoá, bạn có thể so sánh dấu thời gian đó với dấu thời gian của mục first-input để xác định xem hoạt động đầu vào đầu tiên xảy ra trước hay sau quá trình hydrat hoá. Nếu khung của bạn không hiển thị dấu thời gian đó hoặc hoàn toàn không sử dụng lượng nước, thì một tín hiệu hữu ích khác có thể là liệu hoạt động đầu vào xảy ra trước hay sau khi JavaScript tải xong.

Sự kiện DOMContentLoaded sẽ kích hoạt sau khi HTML của trang được tải và phân tích cú pháp hoàn chỉnh, bao gồm cả việc chờ bất kỳ tập lệnh đồng bộ, bị trì hoãn hoặc tập lệnh mô-đun nào (bao gồm tất cả các mô-đun được nhập tĩnh) để tải. Bạn có thể sử dụng thời gian của sự kiện đó và so sánh với thời điểm xảy ra FID.

Mã sau đây quan sát các mục nhập first-input và ghi lại xem hoạt động đầu vào đầu tiên có xảy ra trước khi kết thúc sự kiện DOMContentLoaded hay không:

new PerformanceObserver((list) => {
  const fidEntry = list.getEntries()[0];
  const navEntry = performance.getEntriesByType('navigation')[0];
  const wasFIDBeforeDCL =
    fidEntry.startTime < navEntry.domContentLoadedEventStart;

  console.log('FID occurred before DOMContentLoaded:', wasFIDBeforeDCL);
}).observe({type: 'first-input', buffered: true});

Xác định phần tử mục tiêu FID và loại sự kiện

Các tín hiệu gỡ lỗi có thể hữu ích khác là thành phần được tương tác cũng như kiểu tương tác (chẳng hạn như mousedown, keydown, pointerdown). Mặc dù bản thân hoạt động tương tác với thành phần này không đóng góp vào FID (hãy nhớ rằng FID chỉ là phần trễ của tổng độ trễ của sự kiện), biết những yếu tố nào người dùng đang tương tác có thể hữu ích trong việc xác định cách tốt nhất để cải thiện FID.

Ví dụ: nếu phần lớn lượt tương tác đầu tiên của người dùng là với một phần tử cụ thể, hãy cân nhắc chèn mã JavaScript cần cho phần tử đó vào HTML và tải từng phần còn lại.

Để liên kết loại tương tác và phần tử liên kết với sự kiện nhập đầu tiên, bạn có thể tham khảo các thuộc tính targetname của mục first-input:

new PerformanceObserver((list) => {
  const fidEntry = list.getEntries()[0];

  console.log('FID target element:', fidEntry.target);
  console.log('FID interaction type:', fidEntry.name);
}).observe({type: 'first-input', buffered: true});

INP

INP rất giống với FID ở chỗ các thông tin hữu ích nhất cần thu thập trong trường là:

  1. Phần tử đã được tương tác
  2. Tại sao lại là loại tương tác
  3. Thời điểm diễn ra hoạt động tương tác

Giống như FID, nguyên nhân chính khiến tương tác chậm là luồng chính bị chặn. Điều này có thể xảy ra khi JavaScript đang tải. Việc biết được liệu hầu hết các lượt tương tác chậm có xảy ra trong quá trình tải trang hay không sẽ giúp ích trong việc xác định những việc cần thực hiện để khắc phục vấn đề.

Không giống như FID, chỉ số INP xem xét độ trễ toàn bộ của một lượt tương tác – bao gồm cả thời gian cần để chạy mọi trình nghe sự kiện đã đăng ký, cũng như thời gian cần để vẽ khung tiếp theo sau khi tất cả trình nghe sự kiện đã chạy. Điều này có nghĩa là đối với INP, việc biết được phần tử mục tiêu nào có xu hướng dẫn đến tương tác chậm và những loại tương tác đó thậm chí còn hữu ích hơn.

Vì INP và FID đều dựa trên API Thời gian sự kiện, nên cách bạn xác định thông tin này trong JavaScript rất giống với ví dụ trước. Mã sau đây ghi lại phần tử mục tiêu và thời gian (liên quan đến DOMContentLoaded) của mục nhập INP.

function logINPDebugInfo(inpEntry) {
  console.log('INP target element:', inpEntry.target);
  console.log('INP interaction type:', inpEntry.name);

  const navEntry = performance.getEntriesByType('navigation')[0];
  const wasINPBeforeDCL =
    inpEntry.startTime < navEntry.domContentLoadedEventStart;

  console.log('INP occurred before DCL:', wasINPBeforeDCL);
}

Xin lưu ý rằng mã này không cho biết cách xác định mục nhập event nào là mục nhập INP, vì logic đó có liên quan nhiều hơn. Tuy nhiên, phần sau đây giải thích cách lấy thông tin này bằng thư viện JavaScript web-vitals.

Sử dụng với thư viện web-vitals JavaScript

Các phần trên đưa ra một số đề xuất chung và mã ví dụ để thu thập thông tin gỡ lỗi và đưa vào dữ liệu bạn gửi đến công cụ phân tích.

Kể từ phiên bản 3, thư viện JavaScript web-vitals bao gồm một bản dựng phân bổ hiển thị tất cả các thông tin này cùng một số tín hiệu bổ sung.

Mã ví dụ sau đây cho thấy cách bạn có thể đặt một thông số sự kiện bổ sung (hoặc phương diện tuỳ chỉnh) có chứa chuỗi gỡ lỗi hữu ích trong việc xác định nguyên nhân gốc của các vấn đề về hiệu suất.

import {onCLS, onFID, onINP, onLCP} from 'web-vitals/attribution';

function sendToGoogleAnalytics({name, value, id, attribution}) {
  const eventParams = {
    metric_value: value,
    metric_id: id,
  }

  switch (name) {
    case 'CLS':
      eventParams.debug_target = attribution.largestShiftTarget;
      break;
    case 'LCP':
      eventParams.debug_target = attribution.element;
      break;
    case 'FID':
    case 'INP':
      eventParams.debug_target = attribution.eventTarget;
      break;
  }

  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/ga4
  gtag('event', name, eventParams);
}

onCLS(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
onFID(sendToGoogleAnalytics);
onINP(sendToGoogleAnalytics);

Mã này dành riêng cho Google Analytics, nhưng bạn cũng nên áp dụng ý tưởng chung cho các công cụ phân tích khác.

Mã này cũng chỉ cho biết cách báo cáo về một tín hiệu gỡ lỗi, nhưng việc thu thập và báo cáo nhiều tín hiệu cho mỗi chỉ số có thể hữu ích. Ví dụ: để gỡ lỗi INP, bạn nên thu thập loại tương tác, thời gian và phần tử đang được tương tác. Bản dựng phân bổ web-vitals hiển thị tất cả các thông tin này, như trong ví dụ sau:

import {onCLS, onFID, onINP, onLCP} from 'web-vitals/attribution';

function sendToGoogleAnalytics({name, value, id, attribution}) {
  const eventParams = {
    metric_value: value,
    metric_id: id,
  }

  switch (name) {
    case 'INP':
      eventParams.debug_target = attribution.eventTarget;
      eventParams.debug_type = attribution.eventType;
      eventParams.debug_time = attribution.eventTime;
      eventParams.debug_load_state = attribution.loadState;
      break;

    // Additional metric logic...
  }

  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/ga4
  gtag('event', name, eventParams);
}

onCLS(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
onFID(sendToGoogleAnalytics);
onINP(sendToGoogleAnalytics);

Hãy tham khảo tài liệu về thuộc tính chỉ số quan trọng trên web để biết danh sách đầy đủ các tín hiệu gỡ lỗi được hiển thị.

Báo cáo và trực quan hoá dữ liệu

Sau khi bạn đã bắt đầu thu thập thông tin gỡ lỗi cùng với các giá trị chỉ số, bước tiếp theo là tổng hợp dữ liệu từ tất cả người dùng để bắt đầu tìm kiếm các mẫu và xu hướng.

Như đã đề cập ở trên, bạn không nhất thiết phải giải quyết mọi vấn đề mà người dùng đang gặp phải. Bạn nên giải quyết (đặc biệt là trước tiên), những vấn đề ảnh hưởng đến nhiều người dùng nhất. Đây cũng là những vấn đề có tác động tiêu cực lớn nhất đến điểm số Các chỉ số quan trọng về trang web.

Đối với GA4, hãy xem bài viết riêng về cách truy vấn và trực quan hoá dữ liệu bằng BigQuery.

Tóm tắt

Hy vọng bài đăng này đã giúp nêu ra những cách cụ thể mà bạn có thể sử dụng API hiệu suất hiện có và thư viện web-vitals để lấy thông tin gỡ lỗi nhằm chẩn đoán hiệu suất dựa trên các lượt truy cập thực tế của người dùng tại hiện trường. Mặc dù hướng dẫn này tập trung vào Các chỉ số quan trọng về trang web, nhưng các khái niệm này cũng áp dụng để gỡ lỗi mọi chỉ số hiệu suất có thể đo lường trong JavaScript.

Nếu bạn mới bắt đầu đo lường hiệu suất và đã là người dùng Google Analytics, thì công cụ Báo cáo các chỉ số quan trọng về trang web có thể là nơi phù hợp để bắt đầu vì công cụ này đã hỗ trợ báo cáo thông tin gỡ lỗi cho các chỉ số Chỉ số quan trọng chính của trang web.

Nếu bạn là nhà cung cấp dịch vụ phân tích và đang tìm cách cải thiện sản phẩm cũng như cung cấp thêm thông tin gỡ lỗi cho người dùng, hãy cân nhắc một số kỹ thuật được mô tả ở đây, nhưng đừng chỉ sử dụng chỉ các ý tưởng được trình bày ở đây. Bài đăng này nhằm áp dụng chung cho tất cả các công cụ phân tích; tuy nhiên, từng công cụ phân tích riêng lẻ có thể (và nên) thu thập và báo cáo nhiều thông tin gỡ lỗi hơn nữa.

Cuối cùng, nếu bạn cảm thấy có thiếu sót trong khả năng gỡ lỗi các chỉ số này do thiếu các tính năng hoặc thông tin trong chính API, hãy gửi ý kiến phản hồi đến web-vitals-feedback@googlegroups.com.