優れたユーザーエクスペリエンスを実現するには、高いWebアプリケーションパフォーマンスが不可欠です。 Webアプリケーションがより複雑になるにつれて、パフォーマンスの影響を理解することは、競争力のあるユーザーエクスペリエンスを作成するために不可欠です。 過去数年間にわたって、ネットワークパフォーマンス、ダウンロード時間などを分析できるさまざまなAPIがブラウザーに登場しましたが、アプリケーションを遅くする問題を見つけるのに十分な柔軟性を備えた必要な情報を提供していません。 User Timing APIを使用すると、アプリケーションのどの部分が最も遅いかを判断するメカニズムが提供されます。 この記事では、ユーザータイミングAPIの使用方法と使用方法について説明します。
測定できないものを最適化することはできません
Webアプリケーションを高速化するための最初のステップは、時間の浪費を理解することです。 Javascriptコードの個々の部分の実行にかかる時間を測定することは、ホットスポットを識別する理想的な方法であり、これはパフォーマンスを改善する方法を理解する最初のステップです。 幸いなことに、 ユーザータイミングAPIは、コードのさまざまなセクションにAPI呼び出しを埋め込み、詳細なランタイム情報を取得する方法を提供します。
高解像度時間と「今()」
精度は、真の時間測定の基礎です。 かつてはミリ秒の測定精度でコンテンツを作成できましたが、60 FPSでレンダリングできるサイトの開発は、各フレームを16ミリ秒でレンダリングする必要があることを意味します。 つまり、定性分析にはミリ秒の精度では不十分です。 そこで、最新のブラウザに組み込まれた新しいタイプの時間測定である高解像度時間が導入されました。 高分解能時間は、浮動小数点形式のタイムスタンプを提供します。これにより、測定値がマイクロ秒レベルまで正確になります。これまでよりも数千倍も優れています。
Webアプリケーションの現在の時刻を取得するには 、 Performanceインターフェイスの拡張である ' now() 'メソッドを呼び出します。
var myTime = window.performance.now();
もう1つのインターフェイスPerformancePermingがあります。これは、アプリケーションのロード方法に関する追加情報を提供します。 'now()'メソッドは、PerformanceTimingのnavigationStartイベントが発生してから経過した時間を返します。
タイプDOMHighResTimeStamp
過去にWebアプリケーションのプロファイルを作成しようとした場合、 おそらくDOMTimeStampを返すDate.now()のようなものを処理する必要があります。 DOMTimeStampはミリ秒の整数です。 より高い精度を提供するために、新しいタイプのDOMHighResTimeStampが導入されました。 これは浮動小数点型で、ミリ秒単位の時間も表します。 しかし、そのタイプによって、値はミリ秒の小数部を表すことができ、最大で1000分の1ミリ秒の精度を得ることができます。
ユーザータイミングインターフェース
高解像度のタイムマークを自由に使用できるようになったので、ユーザータイミングインターフェイスを使用して情報を取得できます。 ユーザータイミングインターフェイスは、アプリケーションのさまざまな場所でメソッドを呼び出すことができる機能を提供し、HanselやGretelなどのブレッドクラムに時間コストの場所を追跡させます。
「マーク()」の使用
' mark() 'メソッドは、時間分析ツールキットのメインツールです。 マーク()を使用すると、タイムスタンプを保存できます。 特に便利なのは、タイムスタンプに名前を付ける機能です。
コードのさまざまな部分でmark()を呼び出すと、このマークに到達するまでにかかった時間が決まります。
この仕様では、「mark_fully_loaded」、「mark_fully_visible」、「mark_above_the_fold」など、有用な定義済みのラベルがいくつか提供されています。
たとえば、次のコードを使用して、ラベルを設定して、アプリケーションがいつ完全にロードされたかを判断できます。
window.performance.mark('mark_fully_loaded');
Webアプリケーションで名前付きラベルを設定すると、より多くのランタイム情報を収集して、既存の時間コストを分析するのに役立ちます。
'measure()'を使用した測定値の計算
タイムスタンプを設定したら、それらの間でアプリケーションを実行するのにかかる時間を測定する必要があります。 ' measure() 'メソッドは、この目的のためのものです。 また、タイムスタンプとPerformanceTimingインターフェイスの既知のイベント間の経過時間を計算することもできます。
たとえば、DOMが完全に読み込まれてからアプリケーションが完全に読み込まれるまでの時間を測定できます。
window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');
注:この例では、イベント名「 domComplete 」がPerformanceTimingインターフェースから渡されます。
measure()の呼び出しにより、測定結果がさらに取得できるようになります。 動作中にデータを保存すると、アプリケーションは動作し続け、データは作業終了後も取得できます。
「clearMarks()」でタグを削除する
すでに作成されているタグを取り除くことができると便利な場合があります。 たとえば、プロファイリングの一部としてバッチアプリケーションの起動を行う場合、各起動の前に結果をリセットする必要がある場合、これが必要になる場合があります。 「 clearMarks()」を呼び出すことにより、設定されているタグを簡単に取り除くことができます。
このコードは、既存のすべてのマークを削除します。
window.performance.clearMarks();
もちろん、すべてのタイムスタンプを削除すべきではない状況もあります。 特定のタグを削除する必要がある場合は、削除するタグの名前を渡すだけです。 たとえば、次のコードは、最初の例で設定したマークを削除し、残りはすべて残します。
window.peformance.clearMarks('mark_fully_loaded');
また、以前に行った測定値を削除する必要がある場合があります。対応するメソッド「clearMeasures()」があります。 操作の原理はclearMarks()に似ていますが、マークの代わりに測定値が削除されます。 たとえば、次のコードは、メジャー()に関する前の例で設定されたディメンションを削除します。
window.performance.clearMeasures('measure_load_from_dom');
すべてのディメンションを削除する必要がある場合は、引数なしでclearMeasures()を呼び出すだけです。
データ検索
マークと測定値を設定する機能は便利ですが、ある時点で、その後の分析のためにデータを取得する必要があります。 これも簡単です。PerformanceTimelineインターフェイスを使用するだけです。
たとえば、メソッド ' getEntriesByType() 'を使用すると、すべてのタイムスタンプまたは測定値をリスト形式で取得して、情報をさらに列挙および選択できます。 リストは時系列でコンパイルされるため、タグはWebアプリケーションに配置された順序で表示されます。
以下のコードは、アプリケーションに存在するすべてのマークのリストを返します。
var items = window.performance.getEntriesByType('mark');
次のコードは、すべてのディメンションのリストを返します。
var items = window.performance.getEntriesByType('measure');
名前付きマークのリストを取得することもできます。 たとえば、次のコードは、startTimeプロパティにマーク 'mark_fully_loaded'を含む1つのエントリを持つリストを返します。
var items = window.performance.getEntriesByName('mark_fully_loaded');
XHRリクエストのテスト(例)
これで、ユーザータイミングAPIを簡単に確認した後、それを使用してアプリケーション内のXMLHttpRequestの期間を分析できます。
まず、すべてのsend()リクエストを変更してタイムスタンプを設定し、成功コールバックを別のタイムスタンプを設定してリクエスト期間測定値を生成する関数呼び出しに置き換える必要があります。
通常のXMLHttpRequestは次のようになります。
var myReq = new XMLHttpRequest(); myReq.open('GET', url, true); myReq.onload = function(e) { do_something(e.responseText); } myReq.send();
サンプルコードでは、クエリの数を追跡するグローバルカウンターを追加し、それを使用して完全なクエリごとに測定値を保存する必要があります。
var reqCount = 0; var myReq = new XMLHttpRequest(); myReq.open('GET', url, true); myReq.onload = function(e) { window.performance.mark('mark_end_xhr'); reqCount++; window.performance.measure('measure_xhr_' + reqCnt, 'mark_start_xhr', 'mark_end_xhr'); do_something(e.responseText); }
このコードは、送信されるXMLHttpRequestごとに一意の名前を持つディメンションを生成します。 クエリはシーケンシャルに実行されることを前提としています-並列クエリのコードはもう少し複雑になります。 これは、読者の演習として役立ちます。
Webアプリケーションがすべての要求を行った後、次のコードを使用してコンソールにそれらを表示できます。
var items = window.performance.getEntriesByType('measure'); for (var i = 0; i < items.length; ++i) { var req = items[i]; console.log('XHR ' + req.name + ' took ' + req.duration + 'ms'); }
おわりに
User Timing APIは、Webアプリケーションのあらゆる側面に適用される多くの優れたツールを提供します。 アプリケーションの「ホットスポット」の数を減らすには、アプリケーション全体でAPI呼び出しを使用し、受信したデータを後処理して遅延の図を取得することで簡単に実現できます。 しかし、ブラウザがこのAPIをサポートしていない場合はどうでしょうか? これは問題ではありません。webpagetest.orgテストに合格できる優れたエミュレーションがあります。 待つ価値はありますか? 今すぐUser Timing APIを試してみる価値があります。生産性を高めるための新しい機会があり、ユーザーは感謝の意を表します。