← Back to Tutorials Chapter 7

Caching Strategies

Cache API

The Cache API provides a storage mechanism for Request and Response objects. It's the foundation for all offline strategies.

// Open or create a cache
caches.open('my-cache-v1').then(cache => {
  // Add a single request/response
  cache.add('/api/data.json');

  // Add multiple URLs
  cache.addAll(['/css/styles.css', '/js/app.js']);

  // Manually put a response
  cache.put('/api/data.json', new Response('{"status":"ok"}'));

  // Match a request
  cache.match('/api/data.json').then(response => {
    if (response) { /* use cached response */ }
  });

  // Delete from cache
  cache.delete('/old-asset.js');
});

// List all caches
caches.keys().then(names => console.log(names));

// Delete an entire cache
caches.delete('old-cache-v1');

Common Caching Strategies

1. Cache First (Offline-first)

Return cached content if available; otherwise fetch from network. Best for static assets.

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then(cached => cached || fetch(event.request))
  );
});

2. Network First

Try the network first; fall back to cache if offline. Best for frequently updated content.

self.addEventListener('fetch', (event) => {
  event.respondWith(
    fetch(event.request)
      .then(response => {
        return caches.open('dynamic').then(cache => {
          cache.put(event.request, response.clone());
          return response;
        });
      })
      .catch(() => caches.match(event.request))
  );
});

3. Stale-While-Revalidate

Return cached content immediately, then update the cache with the network response. Best for content that doesn't need instant freshness.

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

4. Network Only / Cache Only

// Network only - always fetch from network
event.respondWith(fetch(event.request));

// Cache only - always serve from cache (fail if not cached)
event.respondWith(caches.match(event.request));

Advanced Patterns

// Pattern: Cache with network update
self.addEventListener('fetch', (event) => {
  if (event.request.url.includes('/api/')) {
    event.respondWith(
      caches.open('api-cache').then(cache => {
        return cache.match(event.request).then(cached => {
          const networkPromise = fetch(event.request).then(response => {
            cache.put(event.request, response.clone());
            return response;
          });
          return cached || networkPromise;
        });
      })
    );
  }
});
Exercise: Implement three different caching strategies for a single-page app: cache-first for static assets (CSS/JS), network-first for blog posts API, and stale-while-revalidate for avatar images. Verify behavior in DevTools under offline mode.