ブラウザで API リクエストにかかった時間を取得する

  • 9
    いいね
  • 0
    コメント

クライアントで API の呼び出しにかかった時間を Resource Timing API を用いて計測する方法を解説します。

Resource Timing API とは

Resource Timing API とは Web ページで読み込まれるリソースの読み込みに要した時間を詳細に取得するための API で、 XMLHttpRequest に限らず <img> などの取得に要する時間を知ることもできます。

Resource Timing API では、その結果を PerformanceResourceTiming というオブジェクトに格納します。PerformanceResourceTimingResource Timing Level 1 で定められており、 2017 年 3 月に Candidate Recommendation となったので、もう使ってしまって問題ないでしょう。

PerformanceResourceTiming を取得する

ある URL に対応する PerformanceResourceTimingPerformance.getEntriesByName を使って取得するコードを以下に示します:

/**
 * @param {String} url
 * @return {?PerformanceResourceTiming}
 */
function getResourceTiming(url) {
  // Performance API が使えない場合は null を返す
  if (!window.performance) return null
  // getEntriesByName が無かったら null を返す。 Safari 9, 10
  if (performance.getEntriesByName) return null
  // 同一 URL に繰り返しリクエストしている場合 resources は複数になる。
  const resources = performance.getEntriesByName(url, "resource")
  // 最後のやつを return する
  return resources[resources.length - 1]
}

たとえばある XMLHttpRequest に対応する PerformanceResourceTiming を求めるには:

getResourceTiming(xhr.responseURL)

各種時間を取得する

取得した PerformanceResourceTiming オブジェクトからリクエストにかかった各種時間を求めます。なおここから先のサンプルコードは次のコード中の /* ここ */ の中にいるものとして記述します。

const resource = getResourceTiming(url)
if (resource) { /* ここ */ }

DNS lookup にかかった時間

resource.domainLookupEnd - resource.domainLookupStart

TCP コネクションにかかった時間

resource.connectEnd - resource.connectStart

SSL ハンドシェイクにかかった時間

resource.connectEnd - resource.secureConnectionStart

リダイレクトにかかった時間

resource.redirectEnd - resource.redirectStart

TTFB (Time To First Byte)

resource.responseStart - resource.startTime

全体の時間

XMLHttpRequest を send してからリダイレクトなども含めて全てのデータを受信し終えるまでにかかった時間は

resource.duration

です。これは resource.responseEnd - resource.startTime と同じです。

クロスオリジン

セキュリティのため Resource Timing API も同一生成元ポリシーに従います。オリジンをまたいで Resource Timing API を使いたい場合 Timing-Allow-Origin ヘッダをつける必要があります。

もし同一生成元ポリシーに引っかかっている場合、生成される PerformanceResourceTiming の以下のプロパティが全て 0 を返すようになります:

  • redirectStart
  • redirectEnd
  • domainLookupStart
  • domainLookupEnd
  • connectStart
  • connectEnd
  • secureConnectionStart
  • requestStart
  • responseStart

そのため、次のようなコードで同一生成元ポリシーに違反したものかどうかを知ることができます:

// 同一生成元ポリシーに違反している場合 false になる
!!response.requestStart

なお同一生成元ポリシーに違反している場合でも duration startTime responseEnd は使うことができます。

参考