Web Storage & Offline

Course 3 · Ch 6
Web Storage & Offline
A quick storage recap, IndexedDB in actual use, and a first look at service workers — the foundation of offline-capable pages
Cross-reference, not a repeat

Cookies, localStorage, sessionStorage, and the conceptual comparison with IndexedDB were already covered thoroughly in the separate Browser Storage, Cookies & Security course's first chapter. This chapter assumes that comparison and goes straight to using IndexedDB practically, plus service workers — the piece that course didn't cover, since it's specifically an HTML/web-app capability rather than a browser-security topic.

IndexedDB in Practice

IndexedDB's API is genuinely more verbose than localStorage's simple get/set — it's asynchronous and event-based, reflecting that it's a real database, not a quick key-value store.

const request = indexedDB.open('NotesApp', 1); request.onupgradeneeded = (event) => { const db = event.target.result; db.createObjectStore('notes', { keyPath: 'id' }); // runs only on first creation or version bump }; request.onsuccess = (event) => { const db = event.target.result; // Writing a record const tx = db.transaction('notes', 'readwrite'); tx.objectStore('notes').add({ id: 1, text: 'Buy milk' }); // Reading it back const getRequest = db.transaction('notes').objectStore('notes').get(1); getRequest.onsuccess = () => console.log(getRequest.result); };
  • onupgradeneeded fires only when the database is first created, or when the version number is bumped — exactly where schema changes (adding object stores, indexes) belong.
  • Object stores are roughly analogous to tables — each with a keyPath defining what makes a record unique.
  • Transactions wrap every read/write — IndexedDB never lets you read or write outside one, ensuring consistency even with concurrent access.
Most real projects use a wrapper library rather than the raw IndexedDB API directly
The verbosity and callback-heavy style above is exactly why libraries like idb (a thin Promise-based wrapper) are extremely common in practice — they provide the same underlying storage with a far more ergonomic, modern async/await-friendly interface. Worth understanding the raw API conceptually, as shown here, even if a wrapper ends up handling the actual implementation in a real project.

Service Workers — A Programmable Network Proxy

A service worker is a script that runs separately from any page, sitting between your web app and the network — it can intercept every network request a page makes and decide how to respond, including serving a cached response when genuinely offline.

Web page fetch request Service Worker cache hit network Cache Real network
The service worker decides, per request, whether to answer from cache or actually go to the network — even fully offline, with no network at all

A Minimal Service Worker — Registration and Caching

// In your main page's JavaScript: if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js'); } // sw.js — the service worker script itself, runs separately const CACHE_NAME = 'my-app-v1'; self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_NAME).then((cache) => cache.addAll(['/', '/styles.css', '/app.js']) ) ); }); self.addEventListener('fetch', (event) => { event.respondWith( caches.match(event.request).then((cached) => cached || fetch(event.request)) ); });

The fetch handler here implements a simple "cache first" strategy: check the cache, serve it if present, fall back to the real network only if not. With this in place, the listed files remain available even with no network connection at all.

Service workers require HTTPS (with one exception)
Browsers refuse to register a service worker over plain HTTP, since it has powerful, security-sensitive capabilities (intercepting all network requests) — the one exception is localhost, which is treated as secure for development purposes. This connects directly back to the security course's HTTPS coverage — yet another reason HTTPS isn't optional for a modern site.
This is genuinely just the foundation — Chapter 7 builds the full PWA picture
A service worker plus a web app manifest (covered next chapter) together make a page genuinely installable, with an icon, offline support, and an app-like presentation — this chapter's caching example is the simplest possible starting point that real Progressive Web Apps build much further on top of.

Chapter 6 Quick Reference

  • IndexedDB — asynchronous, transaction-based; object stores ≈ tables, keyPath defines uniqueness
  • onupgradeneeded — fires only on first creation or version bump; the place for schema changes
  • Most real projects use a wrapper library (e.g. idb) over the raw, verbose IndexedDB API directly
  • Service worker — a separate script intercepting network requests, enabling offline behaviour
  • install event + caches.open/addAll — pre-caching essential files
  • fetch event + caches.match — deciding cache-vs-network per request, the basis of offline support
  • Requires HTTPS (localhost excepted) — same security principle as the cookies/security course
  • Next chapter: Progressive Web Apps — manifest.json, installability basics