Service Worker- Offline Support

Combined with Web Cache, a Service Worker can be used to store resources for offline support, working seamlessly in the background as the main parent script uses the Fetch API:

The ExtendableEvent.waitUntil() method extends the lifetime of the event. If you don't call it inside a method, the service worker could be stopped at any time. So, the waitUntil method is used to tell the browser not to terminate the service worker until the promise passed to waitUntil() is either resolved or rejected.

The respondWith() method of FetchEvent stops the browser's default fetch handling and allows you to provide a promise for a Response yourself.

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('v1').then((cache) => {
      return cache.addAll([
        './sw-test/',
        './sw-test/index.html',
        './sw-test/style.css',
        './sw-test/app.js',
        './sw-test/image-list.js',
        './sw-test/star-wars-logo.jpg',
        './sw-test/gallery/',
        './sw-test/gallery/bountyHunters.jpg',
        './sw-test/gallery/myLittleVader.jpg',
        './sw-test/gallery/snowTroopers.jpg'
      ]);
    })
  );
});
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((resp) => {
      return resp||fetch(event.request).then((response)=>{
        let responseClone = response.clone();
        caches.open('v1').then((cache) => {
          cache.put(event.request, responseClone);
        });
        return response;
      });
    }).catch(() => {
      return caches.match('./sw-test/gallery/myLittleVader.jpg');
    })
  );
});

The experimental Content Index API has been proposed to provide offline support:

On subsequent visits, 'video.html' can be rendered even without a connection to the Internet.
<!DOCTYPE html><html><body>
<p></p>
<script>
var myPage = {
  id: 'myPost',
  url: 'video.html',
  title: 'A nice video.',
  description: 'Here is a nice little video',
  icons: [{
    src: 'doreamon.png',
    sizes: '128x128',
    type: 'image/png',
  }],
  category: 'myCategory'
};
(async()=>{
   const ri = (await navigator.serviceWorker.ready).index;
   const entries = await ri.getAll();
   if (entries.length==0){
      ri.add(myPage);
      console.log('myPage registered for the first time.');
   } else {
      let e = entries[0];
      document.querySelector("p").innerHTML =
        `<a href='${e.url}'>
           <img src='${e.icons[0].src}'/><br/>
           ${e.title}
         </a>`;
   }
})();
</script></body></html>
The API should be available in a service worker script too:
// service worker script
self.registration.index.add(item);
self.registration.index.delete(item.id);
const contentIndexItems = self.registration.index.getAll();
self.addEventListener('contentdelete', (event) => {
  console.log(event.id);   // logs content index id, which can then be used to determine what content to delete from your cache
});