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

Jake Archibald は、デベロッパーのスキルが衰えて落ちていくという懸念を抱きつつも、サービス ワーカーを賢く使用することで、サイトやアプリのパフォーマンスを大幅に改善できると強く主張しています。概要については、動画をご覧ください。

ジェイクが提案するようにページの読み込み時間を短縮するには、サービス ワーカーがページのリクエストにどのように影響するかを理解する必要があります。

Resource Timing API と User Timing API は、多くのサイトの RUM(Real User Monitoring)インフラストラクチャの重要なコンポーネントです。これらの API を使用すると、すべてのユーザーがサイトのパフォーマンスをどのように認識しているかを包括的に把握できます(別のユースケースとして、コンテンツ インジェクションの検出があります)。つまり、サービス ワーカーやウェブワーカーがない限り、サイトから行われたすべてのウェブリクエストのほぼすべての側面を把握できます。

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

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 は、サービス ワーカーがエンジニアの目に留まる前に作成、実装されたため、上記のコードではサービス ワーカーがどのように影響したかを把握できません。

Chrome 45(2015 年 7 月のベータ版)で最近行われた一連の変更により、すべての種類のワーカー(ウェブワーカーとサービス ワーカー)が Resource Timing API と User Timing API にアクセスできるようになりました。これにより、すべてのユーザーのネットワーク パフォーマンスを常に把握できるようになります。

サービス ワーカーからパフォーマンス指標にアクセスする

最大の変更点は、ワーカーのコンテキスト(Web と ServiceWorker)に performance オブジェクトが追加されたことです。これにより、ワーカーのコンテキストで行われたすべてのリクエストのパフォーマンス タイミングを把握できるようになります。また、JS 実行の測定用に独自のマーカーを設定することもできます。現在のウィンドウのコンテキストからのみ発生状況を確認できる場合、次の重要なタイミング情報が失われます。

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

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

どのように使用できますか?

オフライン ファーストをサポートする一般的な 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 コンテキストのパフォーマンス分析を含めるように更新する必要があります。

Navigation Timing API は Service Worker に導入されますか?

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

変更内容を確認できますか?

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