定義
stale-while-revalidate(SWR) は、Service Worker(ページとネットワークの間で fetch を横取りするブラウザスクリプト)が Cache Storage の応答を先に返し、同時に バックグラウンドのネットワークリクエストでキャッシュを更新 する戦略である。キャッシュ miss のときだけネットワーク完了を待つ。
なぜ必要か
ドキュメント・画像のように大きく繰り返し参照されるリソースは、毎回ネットワーク待ちだと体感が遅い。「キャッシュのみ」だと古いファイルが残り、「ネットワークのみ」だと初回表示が遅い。SWR は 初回ペイントを速く、鮮度は裏で 合わせる。
ブラウザ Cache Storage API は 容量上限・LRU 削除を標準提供しない。バイト予算・メタデータはアプリケーションが直接管理する必要がある。
動作原理
fetch イベント
├─ cache.match(key)
│ ├─ hit → respondWith(cached) + waitUntil(revalidate())
│ └─ miss → fetch(network) → put → respondWith
└─ revalidate: fetch → (generation OK なら) put
主要ルール:
- 成功した GET 応答のみ保存。
Range・HEAD・PUTなどはキャッシュせず、部分/破損応答の混入を防ぐ。 - 404・410 は原本削除の信号 — 既存キャッシュ項目も削除する。
- キャッシュキーは presigned-url-cache-key-normalization のように認証クエリだけ除去する。
- 容量: 画像本体 +
{key, bytes, lastAccess}メタを別保存し、総バイトが予算(例: 100MB)を超えたら LRU で削除。 - ヒット時に
lastAccess更新 — 件数ではなく バイト合計 基準がサイズ差の大きい画像に公平。
実務での適用
self.addEventListener("fetch", (event) => {
if (!isImageGet(event.request)) return;
const key = normalizeCacheKey(event.request.url);
const gen = generation;
event.respondWith(
(async () => {
const cached = await caches.match(key);
if (cached) {
event.waitUntil(revalidate(key, gen));
touchMeta(key);
return cached;
}
const fresh = await fetch(event.request);
if (fresh.ok) await putIfCurrent(key, fresh.clone(), gen);
return fresh;
})(),
);
});
- 外部オブジェクトストレージ URL は same-origin プロキシ で統一すると SW scope・cookie 制御が容易。
- 機微画像(マスキング前原本)には SWR 即返却を使わない — cache-generation-stale-write-guard と削除 ACK 順序に従う。
トレードオフ
- SWR は やや古いコンテンツ を一時表示しうる — 一般ドキュメント画像では許容、PII マスキング直後は不可。
- SW 登録・更新・デバッグコストがある。Workbox 等はボイラープレートを減らすが、ポリシー理解は依然必要。
- バックグラウンド revalidate は削除と race — generation guard なしでは削除後に原本が蘇る。
使ってはいけない場合
- 常に最新でなければならない認証トークン・決済結果 API 応答。
Rangeストリーミング・動画シークが核心のメディア(部分キャッシュ汚染)。- SW が使えない環境だけをターゲット — 先にサーバー CDN キャッシュ・HTTP
Cache-Controlだけで足りるか確認。
よくある間違い
- presigned URL クエリ全体 をキーから除去し、マスキング・原本が同一項目で衝突。
- キャッシュ削除だけして in-flight revalidate を止めない。
- 件数制限だけで大画像 1 枚が予算を使い切る、または小サムネだけ LRU で残る。
- ページが SW 制御前に削除メッセージだけ送り無限待機 — タイムアウト・直接
caches.deleteを並行。
関連概念
- presigned-url-cache-key-normalization — 署名クエリ strip・意味クエリ保持
- cache-generation-stale-write-guard — 削除後 stale write 防止
- server-image-proxy-transcoding-cache — サーバープロキシ LRU との役割分担