Chỉ số tuỳ chỉnh

Việc có được những chỉ số phổ quát, tập trung vào người dùng mà bạn có thể đo lường trên bất kỳ trang web nào sẽ giúp bạn hiểu rõ cách người dùng trải nghiệm trên web cũng như trong việc so sánh trang web của bạn với trang web của các đối thủ cạnh tranh. Tuy nhiên, trong nhiều trường hợp, bạn không chỉ cần đo lường các chỉ số chung để có được trải nghiệm đầy đủ cho trang web cụ thể của mình.

Chỉ số tuỳ chỉnh cho phép bạn đo lường các khía cạnh về trải nghiệm trên trang web mà có thể chỉ áp dụng cho trang web của bạn, chẳng hạn như:

  • Khoảng thời gian để một ứng dụng trang đơn (SPA) chuyển đổi từ một "trang" sang "trang khác".
  • Thời gian cần thiết để một trang hiển thị dữ liệu được tìm nạp từ cơ sở dữ liệu cho người dùng đã đăng nhập.
  • Thời gian để một ứng dụng kết xuất phía máy chủ (SSR) để hydrate.
  • Tỷ lệ truy cập vào bộ nhớ đệm đối với các tài nguyên được tải bởi khách truy cập cũ.
  • Độ trễ của sự kiện nhấp chuột hoặc sự kiện bàn phím trong trò chơi.

API để đo lường chỉ số tuỳ chỉnh

Trước đây, các nhà phát triển web chưa từng có nhiều API cấp thấp để đo lường hiệu suất. Vì vậy, họ đã phải dùng đến hành vi tấn công để đo lường xem trang web có hoạt động tốt hay không. Ví dụ: bạn có thể xác định xem luồng chính có bị các tác vụ JavaScript chạy trong thời gian dài chặn hay không bằng cách chạy vòng lặp requestAnimationFrame và tính toán delta giữa mỗi khung. Nếu delta dài hơn đáng kể so với tốc độ khung hình của màn hình, thì bạn có thể báo cáo việc đó dưới dạng một tác vụ dài.

Tuy nhiên, những hình thức tấn công như thế này có thể ảnh hưởng đến hiệu suất của trang web, chẳng hạn như bằng cách làm tiêu hao pin của thiết bị. Nếu các kỹ thuật đo lường hiệu suất tự gây ra vấn đề về hiệu suất, thì dữ liệu bạn nhận được từ các kỹ thuật đó sẽ không chính xác. Do đó, bạn nên sử dụng một trong các API sau để tạo chỉ số tuỳ chỉnh.

API Performance Observer

Hỗ trợ trình duyệt

  • 52
  • 79
  • 57
  • 11

Nguồn

API Performance Observer là cơ chế thu thập và hiển thị dữ liệu từ tất cả các API hiệu suất khác được thảo luận trên trang này. Việc hiểu được mã này là yếu tố cực kỳ quan trọng để nhận được dữ liệu chất lượng cao.

Bạn có thể sử dụng PerformanceObserver để đăng ký thụ động các sự kiện liên quan đến hiệu suất. Điều này cho phép các lệnh gọi lại API kích hoạt trong thời gian không hoạt động, nghĩa là chúng thường sẽ không ảnh hưởng đến hiệu suất của trang.

Khi tạo PerformanceObserver, hãy truyền vào đó một lệnh gọi lại. Lệnh gọi lại này sẽ chạy bất cứ khi nào các mục hiệu suất mới được gửi đi. Sau đó, sử dụng phương thức observe() để cho đối tượng tiếp nhận dữ liệu biết loại mục nhập cần theo dõi như sau:

// Catch errors that some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Log the entry and all associated details.
      console.log(entry.toJSON());
    }
  });

  po.observe({type: 'some-entry-type'});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Các phần sau đây liệt kê tất cả các loại mục nhập mà bạn có thể quan sát. Trong các trình duyệt mới hơn, bạn cũng có thể kiểm tra loại mục nhập hiện có bằng cách sử dụng thuộc tính PerformanceObserver.supportedEntryTypes tĩnh.

Quan sát các mục đã xảy ra

Theo mặc định, các đối tượng PerformanceObserver chỉ có thể quan sát các mục nhập khi chúng xuất hiện. Điều này có thể gây ra sự cố nếu bạn muốn tải từng phần mã phân tích hiệu suất để không chặn các tài nguyên có mức độ ưu tiên cao hơn.

Để lấy các mục nhập trước đây, hãy gọi observe với cờ buffered được đặt thành true. Sau đó, trình duyệt sẽ đưa các mục nhập trước đây vào vùng đệm mục nhập hiệu suất trong lần đầu gọi lệnh gọi lại PerformanceObserver.

po.observe({
  type: 'some-entry-type',
  buffered: true,
});

Các API hiệu suất cũ cần tránh

Trước API Performance Observer, nhà phát triển có thể truy cập vào các mục hiệu suất bằng các phương thức sau được xác định trên đối tượng performance. Bạn không nên sử dụng mã này vì chúng không cho phép bạn theo dõi các mục nhập mới.

Ngoài ra, nhiều API mới (chẳng hạn như Tác vụ dài) không được đối tượng performance hiển thị mà chỉ do PerformanceObserver hiển thị. Do đó, trừ phi bạn thực sự cần khả năng tương thích với Internet Explorer, tốt nhất là nên tránh các phương thức này trong mã của mình và sử dụng PerformanceObserver từ nay về sau.

API Thời gian người dùng

API Thời gian người dùng là một API đo lường đa năng cho các chỉ số dựa trên thời gian. API này cho phép bạn tuỳ ý đánh dấu các điểm theo thời gian và sau đó đo khoảng thời gian giữa các điểm đó.

// Record the time immediately before running a task.
performance.mark('myTask:start');
await doMyTask();
// Record the time immediately after running a task.
performance.mark('myTask:end');

// Measure the delta between the start and end of the task
performance.measure('myTask', 'myTask:start', 'myTask:end');

Mặc dù các API như Date.now() hoặc performance.now() cung cấp cho bạn khả năng tương tự, nhưng API Thời gian người dùng được tích hợp tốt hơn với công cụ hiệu suất. Ví dụ: Công cụ của Chrome cho nhà phát triển trực quan hoá các phép đo Thời gian người dùng trong Bảng điều khiển hiệu suất. Nhiều nhà cung cấp dịch vụ phân tích sẽ tự động theo dõi mọi phép đo mà bạn thực hiện và gửi dữ liệu về thời lượng đến phần phụ trợ phân tích của họ.

Để báo cáo kết quả đo lường Thời gian người dùng, hãy đăng ký PerformanceObserver để quan sát các mục nhập thuộc loại measure:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Log the entry and all associated details.
      console.log(entry.toJSON());
    }
  });
  // Start listening for `measure` entries.
  po.observe({type: 'measure', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Tác vụ dài

Hỗ trợ trình duyệt

  • 58
  • 79
  • x
  • x

Nguồn

API Tác vụ dài rất hữu ích trong việc xác định thời điểm luồng chính của trình duyệt bị chặn đủ lâu để ảnh hưởng đến tốc độ khung hình hoặc độ trễ đầu vào. API báo cáo mọi tác vụ thực thi trong thời gian dài hơn 50 mili giây (mili giây).

Bất cứ khi nào bạn cần chạy mã tốn kém hoặc tải và thực thi các tập lệnh lớn, bạn nên theo dõi xem mã đó có chặn luồng chính hay không. Trên thực tế, nhiều chỉ số cấp cao hơn được xây dựng dựa trên chính API Tác vụ dài (chẳng hạn như Thời gian tương tác (TTI)Tổng thời gian chặn (TBT)).

Để xác định thời điểm diễn ra các thao tác dài, hãy đăng ký PerformanceObserver để quan sát các mục nhập thuộc loại longtask:

// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Log the entry and all associated details.
      console.log(entry.toJSON());
    }
  });
  // Start listening for `longtask` entries to be dispatched.
  po.observe({type: 'longtask', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Thời gian của phần tử

Hỗ trợ trình duyệt

  • 77
  • 79
  • x
  • x

Nguồn

Chỉ số Thời gian hiển thị nội dung lớn nhất (LCP) rất hữu ích khi bạn biết được thời điểm hiển thị khối văn bản hoặc hình ảnh lớn nhất trên trang lên màn hình. Tuy nhiên, trong một số trường hợp, bạn cần đo lường thời gian hiển thị của một phần tử khác.

Đối với những trường hợp này, hãy sử dụng Element Timing API. API LCP thực sự được xây dựng dựa trên API Thời gian phần tử và thêm tính năng báo cáo tự động về phần tử có nội dung lớn nhất. Tuy nhiên, bạn cũng có thể báo cáo về các phần tử khác bằng cách thêm thuộc tính elementtiming một cách rõ ràng vào các phần tử đó và đăng ký PerformanceObserver để quan sát loại mục nhập element.

<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
...
<script>
// Catch errors since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((entryList) => {
    for (const entry of entryList.getEntries()) {
      // Log the entry and all associated details.
      console.log(entry.toJSON());
    }
  });
  // Start listening for `element` entries to be dispatched.
  po.observe({type: 'element', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}
</script>

API Thời gian sự kiện

Chỉ số Thời gian phản hồi lần tương tác đầu tiên (FID) đo lường thời gian từ khi người dùng tương tác với một trang lần đầu tiên cho đến khi trình duyệt có thể bắt đầu xử lý trình xử lý sự kiện để phản hồi hoạt động tương tác đó. Tuy nhiên, trong một số trường hợp, bạn cũng nên đo lường thời gian xử lý sự kiện.

Bạn có thể sử dụng Event Timing API. Ngoài việc đo lường FID, API này còn hiển thị một số dấu thời gian trong vòng đời sự kiện, bao gồm:

  • startTime: thời điểm trình duyệt nhận được sự kiện.
  • processingStart: thời điểm trình duyệt có thể bắt đầu xử lý trình xử lý sự kiện cho sự kiện.
  • processingEnd: thời điểm trình duyệt hoàn tất việc thực thi tất cả các mã đồng bộ được khởi tạo từ trình xử lý sự kiện cho sự kiện này.
  • duration: thời gian (làm tròn thành 8 mili giây vì lý do bảo mật) kể từ khi trình duyệt tiếp nhận sự kiện cho đến khi có thể vẽ khung tiếp theo sau khi hoàn tất quá trình thực thi tất cả mã đồng bộ được khởi tạo qua trình xử lý sự kiện.

Ví dụ sau đây cho biết cách sử dụng các giá trị này để tạo các phép đo tuỳ chỉnh:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  const po = new PerformanceObserver((entryList) => {
    const firstInput = entryList.getEntries()[0];

    // Measure First Input Delay (FID).
    const firstInputDelay = firstInput.processingStart - firstInput.startTime;

    // Measure the time it takes to run all event handlers
    // Doesn't include work scheduled asynchronously using methods like
    // `requestAnimationFrame()` or `setTimeout()`.
    const firstInputProcessingTime = firstInput.processingEnd - firstInput.processingStart;

    // Measure the entire duration of the event, from when input is received by
    // the browser until the next frame can be painted after processing all
    // event handlers.
    // Doesn't include work scheduled asynchronously using
    // `requestAnimationFrame()` or `setTimeout()`.
    // For security reasons, this value is rounded to the nearest 8 ms.
    const firstInputDuration = firstInput.duration;

    // Log these values to the console.
    console.log({
      firstInputDelay,
      firstInputProcessingTime,
      firstInputDuration,
    });
  });

  po.observe({type: 'first-input', buffered: true});
} catch (error) {
  // Do nothing if the browser doesn't support this API.
}

API thời gian tài nguyên

Resource Timing API cung cấp cho nhà phát triển thông tin chi tiết về cách tải các tài nguyên cho một trang cụ thể. Mặc dù có tên là API, nhưng thông tin mà API này cung cấp không chỉ giới hạn ở dữ liệu thời gian (mặc dù có rất nhiều thứ). Những dữ liệu khác mà bạn có thể truy cập bao gồm:

  • initiatorType: cách tìm nạp tài nguyên, chẳng hạn như từ thẻ <script> hoặc <link> hoặc từ fetch().
  • nextHopProtocol: giao thức dùng để tìm nạp tài nguyên, chẳng hạn như h2 hoặc quic.
  • encodedBodySizedecodedBodySize]: kích thước tương ứng của tài nguyên ở dạng được mã hóa hoặc giải mã.
  • transferSize: kích thước của tài nguyên thực sự được chuyển qua mạng. Khi tài nguyên được thực hiện bằng bộ nhớ đệm, giá trị này có thể nhỏ hơn nhiều so với encodedBodySize và trong một số trường hợp, giá trị này có thể bằng 0 nếu không cần xác thực lại bộ nhớ đệm.

Bạn có thể sử dụng thuộc tính transferSize của các mục nhập thời gian tài nguyên để đo lường chỉ số tỷ lệ truy cập vào bộ nhớ đệm hoặc tổng kích thước tài nguyên được lưu vào bộ nhớ đệm. Điều này có thể hữu ích trong việc hiểu được chiến lược lưu tài nguyên vào bộ nhớ đệm ảnh hưởng như thế nào đến hiệu suất của khách truy cập nhiều lần.

Ví dụ sau đây ghi lại tất cả tài nguyên trang web yêu cầu và cho biết liệu mỗi tài nguyên có được thực hiện bằng bộ nhớ đệm hay không:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled via the cache.
      console.log(entry.name, entry.transferSize === 0);
    }
  });
  // Start listening for `resource` entries to be dispatched.
  po.observe({type: 'resource', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Hỗ trợ trình duyệt

  • 57
  • 12
  • 58
  • 15

Nguồn

Navigation Timing API thì cũng tương tự như Resource Timing API, nhưng chỉ báo cáo các yêu cầu điều hướng. Loại mục nhập navigation cũng tương tự như loại mục nhập resource, nhưng chứa một số thông tin bổ sung dành riêng cho các yêu cầu điều hướng (chẳng hạn như khi sự kiện DOMContentLoadedload kích hoạt).

Một chỉ số mà nhiều nhà phát triển theo dõi để nắm được thời gian phản hồi của máy chủ, Thời gian cho byte đầu tiên (TTFB), có sẵn thông qua dấu thời gian responseStart trong Navigation Timing API.

// Catch errors since  browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // If transferSize is 0, the resource was fulfilled using the cache.
      console.log('Time to first byte', entry.responseStart);
    }
  });
  // Start listening for `navigation` entries to be dispatched.
  po.observe({type: 'navigation', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

Một nhà phát triển chỉ số khác sử dụng trình chạy dịch vụ có thể quan tâm đến thời gian khởi động trình chạy dịch vụ cho các yêu cầu điều hướng. Đây là khoảng thời gian cần thiết để trình duyệt bắt đầu luồng trình chạy dịch vụ trước khi có thể bắt đầu chặn các sự kiện tìm nạp.

Thời gian khởi động trình chạy dịch vụ cho một yêu cầu điều hướng đã chỉ định có thể được xác định từ delta giữa entry.responseStartentry.workerStart như sau:

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      console.log('Service Worker startup time:',
          entry.responseStart - entry.workerStart);
    }
  });
  // Start listening for `navigation` entries to be dispatched.
  po.observe({type: 'navigation', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

API Thời gian máy chủ

API thời gian của máy chủ cho phép bạn truyền dữ liệu thời gian dành riêng cho từng yêu cầu từ máy chủ của bạn sang trình duyệt bằng cách sử dụng tiêu đề phản hồi. Ví dụ: bạn có thể cho biết thời gian cần thiết để tra cứu dữ liệu trong cơ sở dữ liệu cho một yêu cầu cụ thể. Việc này có thể hữu ích trong việc gỡ lỗi các vấn đề về hiệu suất do máy chủ hoạt động chậm.

Đối với các nhà phát triển sử dụng nhà cung cấp dịch vụ phân tích bên thứ ba, API Thời gian của máy chủ là cách duy nhất để liên kết dữ liệu hiệu suất của máy chủ với các chỉ số kinh doanh khác mà các công cụ phân tích này đo lường.

Để chỉ định dữ liệu thời gian của máy chủ trong các phản hồi, hãy sử dụng tiêu đề phản hồi Server-Timing. Ví dụ:

HTTP/1.1 200 OK

Server-Timing: miss, db;dur=53, app;dur=47.2

Sau đó, trên các trang của mình, bạn có thể đọc dữ liệu này trên cả hai mục nhập resource hoặc navigation từ API Thời gian tài nguyên và API Thời gian điều hướng.

// Catch errors some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
  // Create the performance observer.
  const po = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      // Logs all server timing data for this response
      console.log('Server Timing', entry.serverTiming);
    }
  });
  // Start listening for `navigation` entries to be dispatched.
  po.observe({type: 'navigation', buffered: true});
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}