Workbox Examples: workbox-runtime-caching

The strategies offered correspond to those listed in the offline cookbook, and that article can help you choose which strategies are appropriate for your different types of requests.

You can see the library in action by making requests for random response data using different strategies. Try disabling your network and see how they handle situations in which a network request fails.


See more details by opening your browser's Developer Tools.

Explore the Code

JavaScript for Service Worker

 * You can extend the base Handler class to implement your own strategies.
class CustomHandler extends workbox.runtimeCaching.Handler {
   * handle() is passed an Object with an event property, and should return a
   * Promise for a Response.
  handle({event}) {
    console.log('CustomHandler is handling', event);
    // this.requestWrapper is a RequestWrapper instance:
    return this.requestWrapper.fetch({
      request: event.request,
    }).catch(() => new Response('Oops! The fetch() failed.'));

 * Initialize all of the different strategies using the default settings.
const strategies = {
  networkOnly: new workbox.runtimeCaching.NetworkOnly(),
  networkFirst: new workbox.runtimeCaching.NetworkFirst(),
  // CacheOnly will always fail, because we don't have the URL precached.
  cacheOnly: new workbox.runtimeCaching.CacheOnly(),
  cacheFirst: new workbox.runtimeCaching.CacheFirst(),
  staleWhileRevalidate: new workbox.runtimeCaching.StaleWhileRevalidate(),
  custom: new CustomHandler(),

 * Set up a fetch handler that uses caching strategy corresponding to the value
 * of the `strategy` URL parameter.
self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url);
  const strategyToUse = url.searchParams.get('strategy');
  if (strategyToUse in strategies) {

 * This is boilerplate, instructing the service worker to take control as soon
 * as it can.
self.addEventListener('install', () => self.skipWaiting());
self.addEventListener('activate', () => self.clients.claim());
JavaScript for this Page
const buttons = document.querySelectorAll('button');
for (const button of [...buttons]) {
  button.addEventListener('click', async () => {
    const url = button.dataset.url;
    window.log('info', `Requesting ${url}...`);
    try {
      const fetchResponse = await fetch(button.dataset.url);
      const fetchBytes = await fetchResponse.text();
      window.log('info', `...fetch() returned '${fetchBytes}'`); 
    } catch (error) {
      window.log('warn', `...fetch failed due to '${error}'.`)
    const cacheResponse = await caches.match(button.dataset.url);
    const cacheBytes = cacheResponse ? await cacheResponse.text() : null;
    window.log('info', cacheBytes ?
        `...the cached entry is '${cacheBytes}'` :
        `...there's no entry in the cache.`);