Using the Resource Timing API

Resource Timing API は、アプリケーションのリソースのロードに関する詳細なネットワークタイミングデータを取得して分析する方法を提供します。アプリケーションはタイミングメトリックを使用して、たとえば、XMLHttpRequest<SVG>、画像、スクリプトなど特定のリソースを取得するのにかかる時間を判断できます。

The interface's properties create a resource loading timeline with high-resolution timestamps for network events such as redirect start and end times, fetch start, DNS lookup start and end times, response start and end times, etc. The interface also includes other properties that provide data about the size of the fetched resource as well as the type of resource that initiated the fetch.

This document shows the use of Resource Timing interfaces. For more details about the interfaces, including examples, see each interface's reference page and the references in the See also section.

A live version of the examples is available on Github, as is the source code. Pull requests and bug reports are welcome.

Resource loading phases

An application can get timestamps for the various phases of resource loading such as redirection, DNS lookup, and TCP connection setup. Those phases and their property names are illustrated in Figure 1.

Graphic of Resource Timing timestamps
Figure 1. Resource timing properties

An application developer can use the property values to calculate the length of time a phase takes and that information can help diagnose performance issues.

Timing resource loading phases

The following example illustrates using the resource timing properties to calculate the amount of time the following phases take: redirection (redirectStart and redirectEnd ), DNS lookup (domainLookupStart and domainLookupEnd), TCP handshake (connectStart and connectEnd), and response (responseStart and responseEnd). This example also calculates the time from the start of the fetch and request start phases (fetchStart and requestStart, respectively), until the response has ended (responseEnd). This timing data provides a detailed profile of the resource loading phases and this data can be used to help identify performance bottlenecks.

function calculate_load_times() {
  // Check performance support
  if (performance === undefined) {
    console.log("= Calculate Load Times: performance NOT supported");
    return;
  }

  // Get a list of "resource" performance entries
  var resources = performance.getEntriesByType("resource");
  if (resources === undefined || resources.length <= 0) {
    console.log("= Calculate Load Times: there are NO `resource` performance records");
    return;
  }

  console.log("= Calculate Load Times");
  for (var i=0; i < resources.length; i++) {
    console.log("== Resource[" + i + "] - " + resources[i].name);
    // Redirect time
    var t = resources[i].redirectEnd - resources[i].redirectStart;
    console.log("... Redirect time = " + t);

    // DNS time
    t = resources[i].domainLookupEnd - resources[i].domainLookupStart;
    console.log("... DNS lookup time = " + t);

    // TCP handshake time
    t = resources[i].connectEnd - resources[i].connectStart;
    console.log("... TCP time = " + t);

    // Secure connection time
    t = (resources[i].secureConnectionStart > 0) ? (resources[i].connectEnd - resources[i].secureConnectionStart) : "0";
    console.log("... Secure connection time = " + t);

    // Response time
    t = resources[i].responseEnd - resources[i].responseStart;
    console.log("... Response time = " + t);

    // Fetch until response end
    t = (resources[i].fetchStart > 0) ? (resources[i].responseEnd - resources[i].fetchStart) : "0";
    console.log("... Fetch until response end time = " + t);

    // Request start until reponse end
    t = (resources[i].requestStart > 0) ? (resources[i].responseEnd - resources[i].requestStart) : "0";
    console.log("... Request start until response end time = " + t);

    // Start until reponse end
    t = (resources[i].startTime > 0) ? (resources[i].responseEnd - resources[i].startTime) : "0";
    console.log("... Start until response end time = " + t);
  }
}

Size matters?

アプリケーションのリソースのサイズはアプリケーションのパフォーマンスに影響を与える可能性があるため、リソースサイズに関する正確なデータを取得することが重要になる可能性があります(特に非ホストリソースの場合)。PerformanceResourceTiming インターフェースには、リソースに関するサイズデータを取得するために使用できる3つのプロパティがあります。 transferSize  プロパティは、レスポンスヘッダフィールドとレスポンスペイロードボディを含む、取得したリソースのサイズ(オクテット単位)を返します。encodedBodySize プロパティは、適用されたコンテンツコーディングを削除する前に、フェッチ(HTTPまたはキャッシュ)から受け取ったサイズ(オクテット単位)を返します。decodedBodySize は、適用されたコンテンツコーディングを削除した後、メッセージ本文のフェッチ(HTTPまたはキャッシュ)から受け取ったサイズ(オクテット単位)を返します。

次の例は、これら3つのプロパティの使い方を示しています。

function display_size_data(){
  // Check for support of the PerformanceResourceTiming.*size properties and print their values
  // if supported.
  if (performance === undefined) {
    console.log("= Display Size Data: performance NOT supported");
    return;
  }

  var list = performance.getEntriesByType("resource");
  if (list === undefined) {
    console.log("= Display Size Data: performance.getEntriesByType() is  NOT supported");
    return;
  }

  // For each "resource", display its *Size property values
  console.log("= Display Size Data");
  for (var i=0; i < list.length; i++) {
    console.log("== Resource[" + i + "] - " + list[i].name);
    if ("decodedBodySize" in list[i])
      console.log("... decodedBodySize[" + i + "] = " + list[i].decodedBodySize);
    else
      console.log("... decodedBodySize[" + i + "] = NOT supported");

    if ("encodedBodySize" in list[i])
      console.log("... encodedBodySize[" + i + "] = " + list[i].encodedBodySize);
    else
      console.log("... encodedBodySize[" + i + "] = NOT supported");

    if ("transferSize" in list[i])
      console.log("... transferSize[" + i + "] = " + list[i].transferSize);
    else
      console.log("... transferSize[" + i + "] = NOT supported");
  }
}

Managing the resource buffer

ブラウザは、リソースタイミングバッファ内で少なくとも150のリソースタイミングパフォーマンスエントリをサポートする必要がありますが、アプリケーションによっては、その制限を超えるリソースを使用することがあります。開発者がバッファサイズを管理しやすくするために、Resource TimingはPerformanceインターフェースを拡張する2つのメソッドを定義します。clearResourceTimings() メソッドは、ブラウザのリソースパフォーマンスエントリバッファからすべての "リソース"タイプのパフォーマンスエントリを削除します。 setResourceTimingBufferSize() メソッドは、リソースパフォーマンスエントリのバッファサイズを、指定された数のリソースに設定しますperformance entries.。

次の例は、これら2つの方法の使用方法を示しています。

function clear_resource_timings() {
  if (performance === undefined) {
    console.log("= performance.clearResourceTimings(): peformance NOT supported");
    return;
  }
  // Check if Performance.clearResourceTiming() is supported
  console.log ("= Print performance.clearResourceTimings()");
  var supported = typeof performance.clearResourceTimings == "function";
  if (supported) {
    console.log("... Performance.clearResourceTimings() = supported");
    performance.clearResourceTimings();
  } else {
    console.log("... Performance.clearResourceTiming() = NOT supported");
    return;
  }
  // getEntries should now return zero
  var p = performance.getEntriesByType("resource");
  if (p.length == 0)
    console.log("... Performance data buffer cleared");
  else
    console.log("... Performance data buffer NOT cleared (still have `" + p.length + "` items");
}

function set_resource_timing_buffer_size(n) {
  if (performance === undefined) {
    console.log("= performance.setResourceTimingBufferSize(): peformance NOT supported");
    return;
  }
  // Check if Performance.setResourceTimingBufferSize() is supported
  console.log ("= performance.setResourceTimingBufferSize()");
  var supported = typeof performance.setResourceTimingBufferSize == "function";
  if (supported) {
    console.log("... Performance.setResourceTimingBufferSize() = supported");
    performance.setResourceTimingBufferSize(n);
  } else {
    console.log("... Performance.setResourceTimingBufferSize() = NOT supported");
  }
}

The Performance interface has a onresourcetimingbufferfull event handler that gets called (with an Event of type Event.type of "resourcetimingbufferfull") when the browser's resource performance entry buffer is full. The following code example sets a onresourcetimingbufferfull event callback in the init() function.

function buffer_full(event) {
  console.log("WARNING: Resource Timing Buffer is FULL!");
  set_resource_timing_buffer_size(200);
}

function init() {
  // load some image to trigger "resource" fetch events
  var image1 = new Image();
  image1.src = "https://developer.mozilla.org/static/img/opengraph-logo.png";
  var image2 = new Image();
  image2.src = "http://mozorg.cdn.mozilla.net/media/img/firefox/firefox-256.e2c1fc556816.jpg"

  // Set a callback if the resource buffer becomes filled
  performance.onresourcetimingbufferfull = buffer_full;
}

Coping with CORS

When CORS is in effect, many of the timing properties' values are returned as zero unless the server's access policy permits these values to be shared. This requires the server providing the resource to send the Timing-Allow-Origin HTTP response header with a value specifying the origin or origins which are allowed to get the restricted timestamp values.

The properties which are returned as 0 by default when loading a resource from a domain other than the one of the web page itself: redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, secureConnectionStart, requestStart, and responseStart.

あわせて参照