Service Worker でのパフォーマンスを測定する

Jake Archibald は、自身の開発者スキルが衰えてなくなることを心配していましたが、Service Worker をインテリジェントに使用することでサイトやアプリのパフォーマンスを劇的に改善できるという強い主張をしました。概要については動画をご覧ください。

Jake が提案するようにページの読み込み時間を大幅に短縮するには Service Worker がページのリクエストに与える影響を

Resource TimingUser Timing API は、多くのサイトの RUM(Real User Monitoring)インフラストラクチャの重要なコンポーネントです。これにより、サイト全体のパフォーマンスを全体的に把握できます(別のユースケースはコンテンツ インジェクションの検出です)。つまり、Service Worker や Web Worker がない限り、サイトから行われるすべてのウェブ リクエストのほぼすべての側面を理解できます。

以下に、現在のドメイン以外のドメインに対して行われたすべてのリクエストのリストを取得する方法の簡単な例を示します。

var getThirdPartyRequests = function() {
    var thirdPartyRequests = [];
    var requests = window.performance.getEntriesByType("resource");
    
    var currentHost = window.location.host

    for(var requestIdx = 0; requestIdx < requests.length; requestIdx++) {
    var request = requests[requestIdx];
    var url = new URL(request.name);
    var host = url.host;

    if(host != currentHost) {
        thirdPartyRequests.push(request);
    }
    }
    
    return thirdPartyRequests;
};

Resource Timing API と User Timing API は、Service Worker がエンジニアに明らかになる前に作成および実装されました。上記のコードでは、Service Worker がどのように影響したかを把握できません。

Chrome 45 の最近の変更(2015 年 7 月ベータ版)では、あらゆる形式のワーカー(ウェブと Service Worker)が Resource Timing API と User Timing API にアクセスできる機能を導入し、すべてのユーザーのネットワーク パフォーマンスを常に把握できるようになります。

Service Worker からパフォーマンス指標へのアクセス

最大の変更点は、Worker のコンテキスト(ウェブと Service Worker)に performance オブジェクトが追加されたことです。これにより、ワーカーのコンテキストで実行されるすべてのリクエストのパフォーマンスのタイミングを把握できるようになり、JS の実行の測定に独自のマークを設定できるようになりました。現在の時間枠のコンテキストから何が起きているかしか確認できない場合、以下の重要なタイミング情報を見逃します。

  • Service Worker の oninstall イベント内で行われた fetch() リクエスト
  • onpush イベントでデータをキャッシュ保存する際に行われた fetch() リクエストをトレースして、ユーザーに表示されるパフォーマンスを把握できるようになりました。
  • 最後に、onfetch ハンドラによって作成およびインターセプトされる fetch() リクエストです。

最後のポイントが重要です。Service Worker は、ウェブ UI とネットワークの間にあるプロキシと考えることができます。windowperformance オブジェクトは、呼び出したリクエストの部分のタイミングと情報のみを確認し、クライアントとネットワークの間にある Service Worker を認識しません。そのため、Service Worker の影響は把握できません。

使い方

最初にオフラインをサポートする一般的な Service Worker には、後で使用するためにすべてのアセットをダウンロードして保存するインストール手順があります。

たとえば、インストール ステップのタイミング データを記録してログに記録することで、実際のユーザーの使用状況に基づいてインストールのパフォーマンスを向上させる方法について測定された決定を下すことができます。

self.addEventListener("install", function() {
    var urls = [
    '/',
    '/images/chrome-touch-icon-192x192.png',
    '/images/ic_add_24px.svg',
    '/images/side-nav-bg@2x.jpg',
    '/images/superfail.svg',
    '/scripts/voicememo-core.js',
    '/styles/voicememo-core.css',
    '/third_party/Recorderjs/recorder.js',
    '/third_party/Recorderjs/recorderWorker.js',
    '/third_party/Recorderjs/wavepcm.js',
    '/third_party/moment.min.js',
    '/favicon.ico',
    '/manifest.json'
    ];

    urls = urls.map(function(url) {
    return new Request(url, {credentials: 'include'});
    });

    event.waitUntil(
    caches
        .open(CACHE_NAME + '-v' + CACHE_VERSION)
        .then(function(cache) {
        // Fetch all the URL's and store in the cache
        return cache.addAll(urls);
        })
        .then(function () {
        // Analyze all the requests
        var requests = self.performance.getEntriesByType("resource");
        
        // Loop across all the requests and save the timing data.
        return;
        })
    );
});

現在、多くのサイトでは、大多数のユーザーがどのようにサイトを利用しているかを把握するために、RUM が使用されています。Google アナリティクスなどのツールでは、すでに Navigation Timing API を使用してサイトの速度データがレポートされていますが、Worker コンテキストからのパフォーマンス分析が含まれるように更新する必要があります。

Service Worker への Navigation Timing API の入手方法

現時点では、Service Worker のコンテキストに Navigation Timing API を追加する予定はありません。これは、Service Worker には従来のナビゲーションがないためです。興味深い点は、Service Worker にとっては、Service Worker が制御するページセット内のすべてのナビゲーションがリソース取得のように見えることです。これだけでも、Service Worker は、パフォーマンス ロジックの大部分をウェブアプリに一元化するための非常に魅力的な方法です。

変更内容を確認する

ディスカッションと仕様に興味がある