Lesson 0002 · ~12 minutes
One skill: use the
named-cache API surface —
caches.open, write with add/put,
read with match — and know what “a match” actually means.
You can sketch open → write → match, explain
add vs put, and flag match-rule gotchas
(query string, method, Vary) in a design review — still without full
service-worker strategies.
Cache Storage is a directory of named caches for the origin. You open one by string name; if it does not exist, it is created (Cache API quick guide):
const cacheAvailable = "caches" in self; // window, worker, or SW
const cache = await caches.open("static-v1");
// cache is a Cache instance for that name
Directory-level helpers on
caches (CacheStorage):
caches.keys() — all names for this origincaches.has(name) / caches.delete(name)caches.match(request) — first hit across
every named cache (vs cache.match on one)
Encode version in the cache name
(static-v3, pages-v2). On activate (or your
cleanup path), delete names you no longer want. Entries do not expire
by themselves
(MDN Cache).
add, addAll, putAll three return promises. New entries overwrite a matching existing entry (quick guide).
You pass URL(s) or Request(s). The browser
fetches and stores only if the response status is
in the 200 range. Failures reject.
addAll rejects if any item fails.
You pass Request/URL and a Response (from
fetch or new Response(...)). More
permissive: can store non-200 and
opaque / non-CORS
responses that add cannot.
const cache = await caches.open("static-v1");
// Network fetch + store (strict)
await cache.add("/app.js");
await cache.addAll(["/app.css", "/index.html"]);
// You control the Response (flexible)
const network = await fetch("/app.js");
await cache.put("/app.js", network.clone()); // clone if you also return network
await cache.put(
"/offline.json",
new Response('{"offline":true}', {
headers: { "Content-Type": "application/json" },
})
);
Cross-origin requests not in CORS mode often yield status
0. add/addAll will not store
them; only put can — and you still cannot inspect the
body/status the way you expect. Prefer CORS (or same-origin) assets
when you need reliable caching and debugging
(quick guide).
match is not “URL equality only”
cache.match(request) resolves to a
Response or undefined. If you pass a string,
the browser builds new Request(string)
(quick guide).
Two requests are treated as different when they differ in more than path — notably query strings, HTTP method, and factors related to Vary. Options let you loosen that:
const hit = await cache.match("/app.js");
const loose = await cache.match(request, {
ignoreSearch: true, // ignore ?query
ignoreMethod: true, // e.g. treat POST like GET for matching
ignoreVary: true,
});
const allHits = await cache.matchAll(request, { ignoreSearch: true });
// if several match without options, match() returns the oldest
List keys (Requests) with cache.keys(); delete one entry
with cache.delete(request) (same match options apply).
| Call | Scope | Typical use |
|---|---|---|
cache.match |
One named cache | You already know which generation (static-v3) |
caches.match |
All named caches | Shortcut; order/which cache wins is “first match” |
cache.matchAll |
One named cache | Multiple variants (e.g. after ignoreSearch) |
Choose the best default. Equal-length options so formatting doesn’t hint. Feedback is immediate.
You need a writable handle to the cache named
static-v2 (create it if missing).
Precache same-origin /app.js only if the network
returns a real success (200-range). Fail the install if it fails.
You already have a cross-origin no-CORS Response (opaque, status
often 0) and still want it in the cache.
Cached as /photo.jpg?w=800 but the page requests
/photo.jpg?w=400. You want one shared entry to match.
After shipping static-v3, remove the whole old
generation named static-v2.
caches.open(name) → one
named cache;
version via the name.
add/addAll = fetch + store OK only;
put = store a Response you already have (more
permissive).
match keys on more than path (query, method, Vary);
loosen with options when intentional.
caches.match searches all names;
caches.delete(name) drops a whole generation.
clone(), opaque sizes, “which cache wins on
caches.match?” — ask in chat. Follow-ups are part of the
method.
web.dev — The Cache API: a quick guide (Pete LePage). Best short primary for this lesson’s method map. Still useful (deferred from lesson 1): Storage for the web for the spectrum you already practiced.