Time to First Byteのキャッシュ期間サブパートを短縮する

キャッシュ期間は、Service Workerとブラウザのキャッシュルックアップ時間を測定します。TTFBを短縮するためのキャッシング戦略、Cache-Controlヘッダー、bfcache、Service Workerの最適化について学びましょう

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-05

Time to First Byteのキャッシュ期間を短縮する

この記事は、Time to First Byte (TTFB)ガイドの一部です。キャッシュ期間はTTFBの2番目のサブパートであり、ブラウザがローカルキャッシュとアクティブなService Workerで一致するレスポンスを確認するのにかかる時間を表します。キャッシュ期間が主要なボトルネックになることはまれですが、Service Workerを使用しているサイトやブラウザキャッシング戦略に大きく依存しているサイトにとって、これを理解することは重要です。

Time to First Byte (TTFB)は、以下のサブパートに分解できます:

Time to First Byteを最適化したいですか? この記事では、Time to First Byteのキャッシュ期間パートについて詳細に分析します。Time to First Byteを理解または改善したいが、キャッシュ期間の意味がわからない場合は、この記事を始める前にTime to First ByteとはTime to First Byteの問題を修正・特定するをお読みください。

注意:通常、Time to First ByteのCache Durationパートはボトルネックにはなりません。次の場合に読み続けてください:a) Service Workerを使用している場合、またはb) 私のようなページスピード愛好家である場合!

Time to First ByteのcacheDurationパートは、待機時間DNSルックアップの間の時間です。この間、ブラウザはブラウザキャッシュまたはService Workerキャッシュで一致するものを探します。Real User Monitoring (RUM)データが高いcacheDurationを示している場合、原因はService Workerの起動とルックアップ時間であるとほぼ確実に言えます。

通常、Time to First Byteのキャッシュ期間サブパートはボトルネックにはならず、10〜20ミリ秒以内に完了します。Service Workerを使用している場合、許容できる時間は60ミリ秒未満です。

Service WorkerはTime to First Byteにどのように影響するか?

Service Workerは、Time to First Byte (TTFB)にプラスとマイナスの両方の影響を与える可能性がありますが、これはService Workerを使用しているウェブサイトに限られます。

Service WorkerがTTFBに影響を与える可能性のある方法は次のとおりです:

Service Workerの起動時間によるTTFBの低下:workerStart値は、要求されたリソースに対してService Workerが存在する場合に、その起動にかかる時間を表します。この起動時間はTTFBの計算に含まれます。Service Workerを起動するか、終了状態から再開する必要がある場合、初期レスポンス時間に遅延が追加され、TTFBが増加する可能性があります。

キャッシングによるTTFBの高速化:stale-while-revalidateなどのキャッシング戦略を使用することで、Service Workerは利用可能な場合にキャッシュから直接コンテンツを提供できます。これにより、頻繁にアクセスされるリソースのTTFBがほぼ瞬時になります。ブラウザがサーバーレスポンスを待つ必要がないためです。この戦略は、最新情報を必要とする動的に生成されたコンテンツよりも、更新頻度の低いコンテンツに最適です。

アプリシェルによるTTFBの高速化:クライアントレンダリングアプリケーションの場合、アプリシェルモデル(Service Workerがキャッシュから基本的なページ構造を提供し、後で動的にコンテンツを読み込む方式)を使用すると、その基本構造のTTFBをほぼゼロに短縮できます。

最適化されていないコードによるTTFBの低下:複雑で非効率なService Workerは、キャッシュルックアッププロセスを遅くし、それによってTTFBも遅くする可能性があります。

Service Workerはページスピードに悪いですか? いいえ(通常は)まったく悪くありません。Service Workerは起動時間のために最初はTTFBを増加させる可能性がありますが、ネットワークリクエストをインターセプトし、キャッシュを管理し、オフラインサポートを提供する能力は、長期的には特にサイトのリピーターに対して、大幅なパフォーマンス向上につながる可能性があります。

Service Workerキャッシング戦略

Service Workerが使用するキャッシング戦略によって、速度と鮮度のバランスが決まります。各戦略は、TTFBのキャッシュ期間サブパートに異なる影響を与えます:

キャッシュファースト(キャッシュからネットワークへのfallback)

Service Workerは最初にキャッシュを確認します。キャッシュされたレスポンスが存在する場合、すぐに返されます。存在しない場合、リクエストはネットワークに送信されます。この戦略は、キャッシュされたリソースに対して最速のTTFBを提供しますが、古いコンテンツを提供するリスクがあります。

最適な用途:静的アセット、画像、フォント、および更新頻度の低いコンテンツ。

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((cachedResponse) => {
      if (cachedResponse) {
        return cachedResponse;
      }
      return fetch(event.request).then((networkResponse) => {
        const cache = await caches.open('v1');
        cache.put(event.request, networkResponse.clone());
        return networkResponse;
      });
    })
  );
});

ネットワークファースト(ネットワークからキャッシュへのfallback)

Service Workerは常にネットワークを最初に試みます。ネットワークリクエストが失敗した場合(例:ユーザーがオフラインの場合)、キャッシュされたバージョンが提供されます。この戦略は、ネットワークが利用可能な場合に新鮮なコンテンツを保証しますが、オンラインユーザーのTTFBは短縮されません。

最適な用途:APIレスポンス、頻繁に更新されるコンテンツ、および鮮度が重要なページ。

Stale-While-Revalidate

Service Workerはキャッシュされたバージョンをすぐに返し(高速なTTFB)、同時にバックグラウンドでネットワークから更新バージョンを取得します。更新バージョンは次回のアクセスのためにキャッシュされたコピーを置き換えます。これは速度と鮮度の間で最適なバランスを取ることが多いです。

最適な用途:定期的に変更されるが、リアルタイムの正確性を必要としないコンテンツ。ニュース記事、ブログ記事、製品一覧など。

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.open('v1').then((cache) => {
      return cache.match(event.request).then((cachedResponse) => {
        const fetchPromise = fetch(event.request).then((networkResponse) => {
          cache.put(event.request, networkResponse.clone());
          return networkResponse;
        });
        return cachedResponse || fetchPromise;
      });
    })
  );
});

Cache-Controlヘッダーの設定

TTFBのキャッシュ期間サブパートはService Workerとブラウザキャッシュのルックアップにかかる時間を具体的に測定しますが、適切なCache-Controlヘッダーはブラウザがサーバーに接続する必要があるかどうかを決定します。正しいキャッシュヘッダーにより、リピーターに対してTTFB全体を効果的にバイパスできます。

異なるリソースタイプに対する推奨Cache-Control設定は次のとおりです:

# HTML pages (always revalidate)
Cache-Control: no-cache

# Static assets with content hashing (cache forever)
Cache-Control: public, max-age=31536000, immutable

# Images without content hashing (cache for 1 week)
Cache-Control: public, max-age=604800

# API responses (no caching)
Cache-Control: no-store

主要なディレクティブの説明:

  • no-cache:ブラウザはキャッシュされたコピーを使用する前に、サーバーで再検証する必要があります。これは「キャッシュしない」という意味ではなく、「常に最初に確認する」という意味です。
  • no-store:ブラウザはレスポンスをまったくキャッシュしてはなりません。機密性の高いコンテンツや非常に動的なコンテンツに使用します。
  • max-age:再検証なしでキャッシュからレスポンスを提供できる秒数です。
  • immutable:リソースが決して変更されないことをブラウザに伝えます。静的アセットに対して、コンテンツハッシュ付きファイル名(例:style.a1b2c3.css)と組み合わせて使用します。
  • public:共有キャッシュ(CDN、プロキシ)によるレスポンスのキャッシュを許可します。ユーザー固有のコンテンツにはprivateを使用します。

CloudflareのようなCDNを使用している場合、エッジキャッシングルールも設定できます。詳細な手順については、パフォーマンスのためのCloudflare設定ガイドをご覧ください。

Back/Forwardキャッシュ(bfcache)

Back/Forwardキャッシュ(bfcache)は、ユーザーがページから離れる際にページの完全なスナップショットをメモリに保存するブラウザの最適化機能です。ユーザーが戻るまたは進むボタンを押すと、ページはメモリから即座に復元され、TTFB(およびその他すべての読み込みメトリクス)が完全に排除されます。

bfcacheから提供されるページは、ネットワークリクエストがまったく行われないため、RUMデータで0ミリ秒のTTFBを示します。ブラウザはメモリ内のスナップショットからページを復元するだけです。

ページがbfcacheの対象となることを確認するには:

  • unloadイベントリスナーを使用しないでください(代わりにpagehideを使用)。
  • HTMLドキュメントにCache-Control: no-storeを使用しないでください。
  • ページが非表示になったとき、開いているIndexedDB接続を閉じてください。
  • アクティブなWebSocketまたはWebRTC接続を保持しないでください(pagehideイベントで閉じてください)。

Chrome DevToolsのApplicationタブ、「Back/Forward Cache」セクションでbfcacheの適格性をテストできます。Chromeは、ページがbfcacheの対象にならなかった理由をリストアップします。

戻る/進むナビゲーションパターンが多いサイト(例:ECのカテゴリーページと商品ページ、検索結果ページ)では、bfcacheはナビゲーションの大部分で体感TTFBを劇的に改善できます。

Time to First Byteのキャッシュ期間サブパートを測定する方法

Time to First Byteのキャッシュ期間サブパートは、次のスニペットで測定できます:

new PerformanceObserver((entryList) => {
  const [navigationEntry] = entryList.getEntriesByType('navigation');

  // get the relevant timestamps
  const activationStart = navigationEntry.activationStart || 0;
  const waitEnd = Math.max(
    (navigationEntry.workerStart || navigationEntry.fetchStart) -
    activationStart,
    0,
  );
  const dnsStart = Math.max(
    navigationEntry.domainLookupStart - activationStart,
    0,
  );

  // calculate the cache duration
  const cacheDuration = dnsStart - waitEnd;

  // log the results
  console.log('%cTTFB cacheDuration', 'color: blue; font-weight: bold;');
  console.log(cacheDuration);

}).observe({
  type: 'navigation',
  buffered: true
});

高いキャッシュ期間によるTTFBの問題を見つける方法

キャッシュ期間が実際のユーザーに与える影響を把握するには、CoreDashのようなRUMツールを使用する必要があります。Real User Monitoringにより、Core Web Vitalsを詳細に追跡できます。

CoreDashでは、「Time to First Byte」に移動して分解の詳細を表示するだけです。これにより、TTFBがすべてのサブパートに分解されて表示され、75パーセンタイルでcacheDurationにかかる時間が正確にわかります。

Service Workerキャッシュ時間の影響を最小限にする方法

Service Worker使用時のTTFBを最適化するには:

  • Service Workerスクリプトの複雑さを最小限にして起動時間を短縮します。
  • Service Worker内で効率的なキャッシング戦略を実装します(ナビゲーションリクエストにはstale-while-revalidateを推奨)。
  • Service Workerのインストール時に重要なリソースをプリキャッシュすることを検討してください。
  • Service WorkerがサイトのTTFBに与える影響を定期的に監視・分析してください。
  • navigation preloadを使用して、ネットワークリクエストをService Workerの起動と並行して行えるようにします。これにより、Service Workerの起動時間がTTFBに加算されるのを防ぎます。

Service Workerでnavigation preloadを有効にするには:

self.addEventListener('activate', (event) => {
  event.waitUntil(
    (async () => {
      if (self.registration.navigationPreload) {
        await self.registration.navigationPreload.enable();
      }
    })()
  );
});

Service Workerの実装を慎重に管理し、TTFBへの影響を理解することで、開発者は初期のオーバーヘッドとService Workerが提供する長期的なパフォーマンスの利点のバランスを取ることができます。

関連情報:最適化ガイド

キャッシングとTTFBに影響する関連最適化テクニックについては、以下のガイドをご覧ください:

  • 103 Early Hints:サーバーレスポンスの準備が整う前に重要なリソースの読み込みを開始し、キャッシング戦略を補完します。
  • パフォーマンスのためのCloudflare設定:CDNエッジキャッシング、キャッシュルール、ページルールを設定して、エッジレベルでキャッシング戦略を最適化します。

TTFBサブパート:詳細記事

キャッシュ期間はTTFBの5つのサブパートの1つです。他のサブパートを確認して、全体像を理解しましょう:

見張るのをやめた瞬間にパフォーマンスは劣化します。

監視、バジェット、運用プロセスまで組みます。一時的な修正と本当の解決の差はここです。

一度お話ししませんか
Time to First Byteのキャッシュ期間サブパートを短縮するCore Web Vitals Time to First Byteのキャッシュ期間サブパートを短縮する