パフォーマンス、パフォーマンス、パフォーマンス。 あなたは世界で最高のウェブサイトを持つことができますが、ロードするのに2分かかると、誰もそれを見ることができません。 あなたのウェブサイトがロードするのに2分かかるなら、それはおそらく理由を理解するのにそれほど難しいことではないでしょう。 平均ロード時間を1秒から0.85秒に短縮しようとすると、最適化が難しくなります。

アプリケーションがローカルでどのように機能するかを理解するのに役立つツールはたくさんあります。 Performance APIは、実際のWebページを詳細に理解するのに役立ちます。 実際のデータを取得して、さまざまなブラウザ、ネットワーク、世界の一部などでサイトがどのように機能するかを確認できます。

Performance APIは、多くの場合、APIのコンステレーションとして説明されます。 1つの記事ですべてを説明するには多すぎます。 この投稿では、パフォーマンスの監視を開始するための最も基本的な機能を紹介します。

APIは進化しており、今後多くの新機能と非推奨があります。 今後登場するすべてのパフォーマンスAPIのレベル2。 それらのいくつかは部分的に実装されています、それらのいくつかはまだドラフトです。 したがって、最新の更新については、MDNまたはW3CのWebサイトを定期的にチェックする必要があります。

パフォーマンスデータにアクセスする方法

performance.now

プログラムのパフォーマンスを測定する最も基本的な方法は、 performance.now(). これにより、現在の時刻がミリ秒未満の解像度で返されます。 高解像度の時間を掘り下げたい場合は、そのトピックに関するW3Cの編集者のドラフトを読むことを強くお勧めします。

performance.now JavaScriptコードの内容(ユーザーパフォーマンス)のみを測定できます。 この投稿の後半で、performance.nowの使用例について説明します。


さまざまなDOMおよびブラウザイベントにアクセスするために、次の3つの機能があります。

  • getEntries() 使用可能なすべてのパフォーマンスエントリを返します。 実行してみてください performance.getEntries() 現在のページに、大きな配列が表示されます。 最初は、ほとんどのエントリは、ページ(別名リソース)によって読み込まれるすべての画像、スクリプト、およびその他のものに関連しています。
const tenthEntry = performance.getEntries()[10]
// on Alligator.io it will return the following object
// { initiatorType: "script",
// nextHopProtocol: "h2",
// workerStart: 526.8099999520928,
// redirectStart: 0,
// ....
// decodedBodySize: 0,
// serverTiming: [],
// name: "https://d33wubrfki0l68.cloudfront.net/bundles/e2203d1b1c14952473222bcff4c58a8bd9fef14a.js",
// entryType: "resource",
// startTime: 315.5049999477342,
// duration: 231.48499999661
//}
// We can see this is a resource entry for a script loaded from cloudfront
  • getEntriesByType()は次のようなものです getEntries()、ただし、結果をフィルタリングする可能性があります。

クエリできるタイプは6つあります。

  • フレーム:非常に実験的な機能で、開発者は1つのイベントループでブラウザによって実行された作業量に関するデータを取得できます。 ブラウザが1つのループで多くの作業を行っていると、フレームレートが低下し、ユーザーエクスペリエンスが低下します。
  • リソース:これは、サイトによってダウンロードされるすべてのリソースに関連しています。
  • マーク:これらは、コードの速度を計算するために使用できるカスタムマーカーです。
  • 測定:測定により、2つのマークの差を簡単に測定できます。
  • ペイント:ペイントエントリは、画面に表示されるピクセルに関連しています。
  • longtask:長いタスクは、実行に50ミリ秒以上かかるタスクです。

次のセクションでは、これらのタイプのいくつかについて詳しく説明します。 開始する簡単な例を次に示します。

const paintEntries = performance.getEntriesByType('paint')
// paint Entries[0] equals {
//    name: "first-paint",
//    entryType: "paint",
//    startTime: 342.160000000149,
//    duration: 0,
//    }
// paintEntries[1] equals {
//    name: "first-contentful-paint",
//    entryType: "paint",
//    startTime: 342.160000000149,
//    duration: 0,
// }
  • getEntriesByName(entryName)は、すべてのエントリを名前でフィルタリングします。
const nativeLogoPerfEntry = performance.getEntriesByName('https://alligator.io/images/alligator-logo3.svg')[0];
// It will return performance information related to the logo's performance:
// {initiatorType: "img",
// nextHopProtocol: "",
// workerStart: 539.6649999311194,
// ........
// name: "https://alligator.io/images/alligator-logo3.svg",
// entryType: "resource",
// startTime: 539.5149999530986,
// duration: 94.24000000581145
//}

サイトのパフォーマンスに関するより高いレベルの情報を探している場合は、電話することもできます performance.toJSON().

機能を監査する

特定のJavaScript関数を監査するための最も基本的なツールは、 performance.now() 上記で説明しました。

使用例は次のとおりです。

const firstNow = performance.now()
// This loop is just to simulate slow calculations
for (let i = 0; i < 100000; i++){
  var ii = Math.sqrt(i)
}
const secondNow = performance.now()

const howLongDidOurLoopTake = secondNow - firstNow
// on my laptop it returns howLongDidOurLoopTake == 4.08500000089407 in milliseconds

の問題 now 多くの測定値がある場合、管理が少し難しいということです。 より便利なツールは mark これにより、後でクエリできるパフォーマンスエントリがいくつか作成されます。 次に、マーカーを組み合わせて、を使用して新しいエントリを作成できます measure.

performance.mark('beginSquareRootLoop');
// This loop is just to simulate slow calculations
for (let i = 0; i < 1000000; i++){
  var ii = Math.sqrt(i);
}
performance.mark('endSquareRootLoop');
// Then anywhere in your code you can use

// We create a new entry called measureSquareRootLoop which combines our two marks
performance.measure('measureSquareRootLoop','beginSquareRootLoop', 'endSquareRootLoop');

console.log(performance.getEntriesByName('beginSquareRootLoop'));
// {detail: null,
// name: "beginSquareRootLoop",
// entryType: "mark",
// startTime: 3745.360000000801,
// duration: 0}

console.log(performance.getEntriesByName('measureSquareRootLoop'));
// {detail: null,
// name: "measureSquareRootLoop",
// entryType: "measure",
// startTime: 3745.360000000801, This is the same as beginSquareRootLoop
// duration: 9.904999984428287 shows the time it took to get from beginSquareRootLoop to endSquareRootLoop
//}

ナビゲーションは、Webページを構築するための重要な手順を詳細に理解するために使用されます。 ナビゲーションデータにアクセスする最も安全な方法は、次のことです。

const navigationEntry = performance.getEntriesByType('navigation')[0]

私のブラウザでは、次のようになります。

{
  unloadEventStart: 213.41000002576038,
  unloadEventEnd: 213.41000002576038,
  domInteractive: 975.8100000326522,
  domContentLoadedEventStart: 982.2649999987334,
  domContentLoadedEventEnd: 1217.9650000180118,
  domComplete: 2000.960000033956,
  loadEventStart: 2001.044999982696,
  loadEventEnd: 2008.6500000325032,
  type: "reload",
  redirectCount: 0,
  initiatorType: "navigation",
  nextHopProtocol: "",
  workerStart: 2.5550000136718154,
  redirectStart: 0,
  redirectEnd: 0,
  fetchStart: 2.5599999935366213,
  domainLookupStart: 2.5599999935366213,
  domainLookupEnd: 2.5599999935366213,
  connectStart: 2.5599999935366213,
  connectEnd: 2.5599999935366213,
  secureConnectionStart: 0,
  requestStart: 2.5599999935366213,
  responseStart: 107.46500000823289,
  responseEnd: 214.3950000172481,
  transferSize: 0,
  encodedBodySize: 0,
  decodedBodySize: 0,
  serverTiming: [],
  name: "https://alligator.io/",
  entryType: "navigation",
  startTime: 0,
  duration: 2008.6500000325032
}

今後の投稿で、そのデータの使用方法についてさらに詳しく説明します。 しかし、それまでの間、ここにナビゲーションタイムラインの視覚化があります:

リソース

リソースがページによってロードされるときはいつでも、パフォーマンスエントリでそのトレースを見つけることができます。 それらを取得するために私たちがしなければならないのは実行されるだけです performance.getEntriesByType('resource'). これには、画像、スクリプト、CSSファイルなどが含まれます。 たとえば、サイト上の画像のパフォーマンスに焦点を当てたい場合は、次のように実行できます。

performance.getEntriesByType('resource').filter(resource=> resource.initiatorType == 'img')

Alligator.ioにあるリソースの1つは次のとおりです。

{
    initiatorType: "img",
    nextHopProtocol: "h2",
    workerStart: 551.2149999849498,
    redirectStart: 0,
    redirectEnd: 0,
    fetchStart: 551.3149999896996,
    domainLookupStart: 0,
    domainLookupEnd: 0,
    connectStart: 0,
    connectEnd: 0,
    secureConnectionStart: 0,
    requestStart: 0,
    responseStart: 0,
    responseEnd: 560.1850000093691,
    transferSize: 0,
    encodedBodySize: 0,
    decodedBodySize: 0,
    serverTiming: [],
    name: "https://d33wubrfki0l68.cloudfront.net/39d2d2905588dad289b228deb021d51449f6143d/a3baf/images/logos/gatsby-logo.svg",
    entryType: "resource",
    startTime: 222.0450000022538,
    duration: 338.1400000071153
}

ご覧のとおり、このエントリには多くの0値があります。これは、CORSによって制限されているためです(これは、リソースタイミングAPIの大きな制限です)。 したがって、次のプロパティは常に0を返します:redirectStart、redirectEnd、domainLookupStart、domainLookupEnd、connectStart、connectEnd、secureConnectionStart、requestStart、およびresponseStart。

ペイント

paint APIは、ウィンドウにピクセルを描画するイベントに関連しています。 前のスニペットで見たように、 First Time toPaintおよびFirstContentfulPaintにアクセスできます。 Lighthouseのようなフロントエンド最適化ツールを使用したことがある場合は、これらの用語に精通している可能性があります。 初めてペイントするのは、最初のピクセルがユーザー画面に表示されたときです。 最初の満足のいくペイントは、DOMで定義された要素が最初にレンダリングされるときです。 最初のコンテンツの多いペイントを最適化するには、レンダリングをブロックするスクリプトとスタイルシートを減らし、HTTPキャッシングを使用し、JavaScriptの起動を最適化します。

これらは便利な指標ですが、ユーザーに何が表示されるかを理解しようとしている場合はかなり制限されます。 ユーザーのパフォーマンスの認識を把握するには、複数の指標を組み合わせる必要があります。

パフォーマンスAPIは巨大であり、急速に変化しています。 更新を探すのに最適な場所はもちろんAlligator.ioですが、このトピックを本当に深く掘り下げたい場合は、 Web PerformanceWorkingGroupのページをチェックしてください。最新のワーキングドラフトと推奨事項を見つけます。