Cache-First Strategy
A cache-first strategy serves a cached response when one exists and otherwise requests the resource from the network. In service workers, it can improve speed and provide resilience when connectivity is unavailable.
A cache-first strategy checks the Cache Storage API before making a network request. If a matching cached response is found, the service worker returns it immediately, avoiding the network for that request.
If the cache does not contain a matching response, the service worker fetches the resource from the network. A successful network response can then be stored in the cache so later requests can be served locally.
This approach is useful for resources that do not need to be completely fresh on every request, such as application assets or relatively stable content. The main trade-off is freshness: a cached response can become outdated unless the application has an explicit invalidation or update strategy.
In a service worker, the `fetch` event is commonly used to intercept requests, while `caches.match()` searches available caches and `cache.put()` stores a response. A robust implementation also considers non-GET requests, failed network responses, cache versioning, and whether the response is suitable for caching.
Key points
- Check the cache before accessing the network.
- Use the network as the fallback when no cached match exists.
- Cache successful network responses when later reuse is desired.
- Cache-first favors latency and offline resilience over immediate freshness.
- Use cache versioning or invalidation to prevent stale resources from persisting indefinitely.
Interview questions
What is a cache-first strategy in a service worker?
A cache-first strategy checks Cache Storage before requesting a resource from the network. If a matching response exists, the service worker returns it immediately. If there is no match, it fetches the resource from the network and can cache the successful response. This reduces latency and can support offline use for resources that have already been cached.
Why might cache-first return stale content?
The strategy intentionally prefers an existing cached response over the network. If that cached response represents an older version of the resource, the service worker can return it without checking whether the server has newer content. Applications therefore need cache invalidation, versioned cache names, or another update mechanism when freshness matters.
Why is `response.clone()` often needed when caching a fetched response?
A fetch response has a body that is consumed through a stream. If application code returns the response while cache code also needs to consume its body, both operations cannot safely consume the same stream independently. Cloning creates another response whose body can be consumed by the cache operation. The original response can then be returned to the browser.
What types of resources are commonly suitable for cache-first?
Cache-first is commonly useful for resources whose cached version remains acceptable for some period, such as static application assets. The exact choice depends on freshness requirements and how the application updates those resources. Frequently changing or user-specific data may need a different strategy. A good design considers both performance and the consequences of serving older data.
How would you make a cache-first service worker safer for production?
I would define explicit caching rules instead of caching every request indiscriminately. I would version cache names, remove obsolete caches during service-worker activation, validate responses before storing them, and consider request methods and destinations. I would also choose strategies according to freshness and consistency requirements rather than applying cache-first globally. Finally, I would test deployment updates, offline behavior, and failure cases.