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:
- During the
install
event, static resources are cached, and user data is fetched from an API and stored in IndexedDB. - 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.
Top comments (0)