Workbox Examples: workbox-broadcast-cache-update

The most common use case would be to have a service worker compare a previously cached response with a response from the network, so that you can let pages know that updated data was received.

Note that the comparison is done via one or more headers, not response bodies, for efficieny's sake. Also note that cross-origin responses using the CORS protocol only expose a subset of response headers. The remote server needs to explicitly whitelist headers by setting Access-Control-Allow-Headers or the headers won't be visible on the CORS response.

, which will trigger a BroadcastChannel API message whenever the Date: header differs from the Date: in the cached entry.

Messages

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

Explore the Code

JavaScript for Service Worker
importScripts('https://unpkg.com/workbox-broadcast-cache-update@2.0.3/build/importScripts/workbox-broadcast-cache-update.prod.v2.0.3.js');

// Set up some constants used later on.
const testFileUrl = new URL('test.txt', location).toString();
const cacheName = 'workbox-broadcast-cache-update-example';

const broadcastCacheUpdate =
  new workbox.broadcastCacheUpdate.BroadcastCacheUpdate({
  // Choose whatever channel name you'd like. You can also set up multiple
  // instances that broadcast to different channel names.
  channelName: 'test-file-updates',
  // The default headers are ['content-length', 'etag', 'last-modified'].
  // None of those headers will be different when we refetch our test file,
  // though, so we'll check for 'date', which will change eventually.
  headersToCheck: ['date'],
  // You can use any identifying string here.
  source: 'broadcast-cache-update-example',
});

const testFileHandler = async () => {
  const networkResponse = await fetch(testFileUrl);
  const cache = await caches.open(cacheName);
  const cacheResponse = await cache.match(testFileUrl);

  // If there isn't a response already in the cache, then skip checking to see
  // if there's an update.
  if (cacheResponse) {
    broadcastCacheUpdate.notifyIfUpdated({
      first: cacheResponse,
      second: networkResponse,
      url: testFileUrl,
      cacheName,
    });
  }

  await cache.put(testFileUrl, networkResponse.clone());

  return networkResponse;
};

/**
 * Set up a fetch handler that only responds to requests for the test file.
 */
self.addEventListener('fetch', (event) => {
  if (event.request.url === testFileUrl) {
    event.respondWith(testFileHandler());
  }
});

/**
 * 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 response = await fetch(button.dataset.url);
      window.log('info', `...request complete. Date header is '${response.headers.get('date')}'`);
    } catch (error) {
      window.log('warn', `...fetch failed due to '${error}'.`);
    }
  });
}

// This code sets up a listener for messages broadcast to 'test-file-updates'.
// Those messages will come from the service worker if the response for a file
// received from the network is different from the previously cached response.
const updatesChannel = new BroadcastChannel('test-file-updates');
updatesChannel.addEventListener('message', (event) => {
  window.log('info', `The network response has a different Date: header than the cached response: ${JSON.stringify(event.data)}`);
});