Skip to main content

Command Palette

Search for a command to run...

PWA Offline Storage Strategies-IndexedDB and Cache API

Published
4 min read
PWA Offline Storage Strategies-IndexedDB and Cache API
T

I focus on the long-term foundations of computer science, software engineering, and emerging technologies.covering computer science, AI, semiconductors, quantum computing, and future engineering.

Progressive Web Apps (PWAs) utilize offline storage strategies to provide an offline experience, enabling access to some content even when the network is unavailable. The two primary offline storage technologies are IndexedDB and the Cache API (also known as Service Worker Cache). Each has distinct features and is suited for different use cases.

IndexedDB

IndexedDB is a key-value store ideal for storing large amounts of structured data, such as database records, user settings, or large files. It supports complex queries and transactional operations. Below is an example of creating, storing, and retrieving data with IndexedDB:

// Open or create a database
let dbPromise = indexedDB.open("myDatabase", 1);

// When the database opens successfully
dbPromise.then(function(db) {
    // Create an object store
    let objectStore = db.createObjectStore("myStore", { keyPath: "id" });

    // Insert data
    objectStore.add({ id: 1, name: "Alice" });

    // Query data
    let transaction = db.transaction(["myStore"], "readonly");
    let store = transaction.objectStore("myStore");
    let request = store.get(1);

    request.onsuccess = function(event) {
        console.log("Retrieved data:", event.target.result);
    };
});

Cache API

The Cache API, part of Service Workers, is used to cache network requests and responses, typically for static resources. It provides a straightforward way to store and retrieve resources based on their URLs. Below is an example of using the Cache API to cache web resources:

// Cache resources during the install phase in the service worker
self.addEventListener("install", async event => {
    event.waitUntil(
        caches.open("myCache").then(cache => {
            return cache.addAll([
                "/index.html",
                "/styles.css",
                "/scripts.js"
            ]);
        })
    );
});

// Handle fetch events by attempting to retrieve resources from the cache
self.addEventListener("fetch", event => {
    event.respondWith(
        caches.match(event.request).then(response => {
            // Return cached response if available
            if (response) {
                return response;
            } else {
                // Otherwise, fetch from the network and cache the new resource
                return fetch(event.request).then(networkResponse => {
                    caches.open("myCache").then(cache => {
                        cache.put(event.request, networkResponse.clone());
                    });
                    return networkResponse;
                }).catch(() => {
                    // Return a cached fallback response if the network fails
                    return caches.match("/offline.html");
                });
            }
        })
    );
});

Code Breakdown:

  • The install event initializes the cache, adding specified URLs to it.

  • The fetch event listens for network requests, prioritizing cached resources. If no cache exists, it fetches from the network, caches the new resource, and returns it. If the network request fails, a fallback offline page is returned.

By combining IndexedDB and the Cache API, PWAs can store both user data and static resources offline, ensuring a robust user experience even without a network connection.

In real-world PWA applications, IndexedDB and the Cache API are often used together to achieve optimal offline experiences. For example, IndexedDB stores user data, while the Cache API handles static resources.

self.addEventListener("install", async event => {
    event.waitUntil(
        Promise.all([
            caches.open("staticCache").then(cache => {
                return cache.addAll([
                    "/index.html",
                    "/styles.css",
                    "/scripts.js"
                ]);
            }),
            // Assume an API fetches user data
            fetch("/api/user").then(response => {
                return response.json().then(data => {
                    return indexedDB.open("userData", 1).then(db => {
                        let transaction = db.transaction(["userData"], "readwrite");
                        let store = transaction.objectStore("userData");
                        store.put(data);
                    });
                });
            })
        ])
    );
});

self.addEventListener("fetch", event => {
    event.respondWith(
        caches.match(event.request).then(response => {
            if (response) {
                return response;
            }

            // Try fetching from the network
            return fetch(event.request).then(networkResponse => {
                caches.open("staticCache").then(cache => {
                    cache.put(event.request, networkResponse.clone());
                });

                return networkResponse;
            }).catch(() => {
                // If network fails, try fetching user data from IndexedDB
                if (event.request.url.endsWith("/api/user")) {
                    return indexedDB.open("userData", 1).then(db => {
                        let transaction = db.transaction(["userData"], "readonly");
                        let store = transaction.objectStore("userData");
                        let request = store.get(1);
                        return request.onsuccess ? request.onsuccess.event.target.result : null;
                    });
                } else {
                    return caches.match("/offline.html");
                }
            });
        })
    );
});

Code Breakdown:

  1. During the install event, static resources are cached, and user data is fetched from an API and stored in IndexedDB.

  2. During the fetch event, resources are first retrieved from the cache. If unavailable, the network is queried. For API requests, if the network fails, user data is retrieved from IndexedDB. For other resources, a fallback offline page is returned.

2 views

Web Development

Part 1 of 46

The content covers the three basics of HTML/CSS/JS/TS, modular development, mainstream frameworks (Vue, React, Angular, Svelte), build tools, browser plug-in development, Node.js backend practice, Next.js/Nest.js and other popular technologies.

Up next

WebGL and Three.js-3D Graphics Applications on the Web

WebGL (Web Graphics Library) is a JavaScript API that enables hardware-accelerated 3D graphics rendering in any compatible web browser without the need for plugins. Based on the OpenGL standard, it in