Understanding Browser Database IndexedDB and Using localForage
This article explains the architecture, features, and compatibility of IndexedDB, compares it with traditional storage options, introduces the localForage library for simplified asynchronous storage, and provides practical code examples for managing data and caching video content in web applications.
Existing browser storage solutions are unsuitable for large amounts of data: cookies are limited to 4 KB and are sent with every request; LocalStorage provides only a few megabytes and lacks search or custom indexing capabilities. IndexedDB is a non‑relational, NoSQL‑like database designed for key‑value storage.
IndexedDB Architecture
In IndexedDB the smallest unit is a key‑value pair, which corresponds to a record in a relational database. The database contains objectStore objects (analogous to tables) and each record is stored directly as a key‑value pair without predefined fields. Transactions are built‑in, and all read/write operations occur within a transaction.
Both IndexedDB and SQL databases have the concept of a database.
SQL databases have tables; IndexedDB uses objectStore .
SQL records have columns; IndexedDB records are simple key‑value pairs.
Although an objectStore resembles a SQL table, its storage format is much simpler, and all operations are transaction‑based.
Indexes
Indexes are a core feature of IndexedDB, allowing queries on arbitrary object properties rather than just the primary key. An index is defined outside the objectStore but bound to it, providing additional lookup paths.
Without an index you can only query by the primary key; with an index you can query by any attribute path.
Key Features of IndexedDB
Key‑value storage : Stores any JavaScript object; each record has a unique primary key.
Asynchronous : Operations do not block the UI, unlike the synchronous LocalStorage.
Transactional : A failure in any step rolls back the entire transaction.
Same‑origin restriction : Databases are scoped to the origin that created them.
Large storage quota : Typically at least 250 MB, varying by browser and device.
Binary support : Can store ArrayBuffer and Blob objects.
Compatibility
IndexedDB is supported by all major browsers; see caniuse.com for detailed tables.
Browser Storage Quota
Web storage APIs allow developers to query available storage using the StorageManager API, test quota exhaustion with simple tools, handle QuotaExceededError , and understand browser eviction policies.
localForage
localForage is a JavaScript library that provides an asynchronous API similar to LocalStorage but stores data using IndexedDB, WebSQL (deprecated), or falls back to LocalStorage. It supports storing any data type, not just strings, and works across Chrome, Firefox, IE, and Safari (including Safari Mobile).
Usage
// callback form
localforage.setItem('key', 'value', function(err) {
// if err is non‑null, we got an error
localforage.getItem('key', function(err, value) {
// if err is non‑null, we got an error. otherwise, value is the value
});
});
// Promise form
localforage.setItem('key', 'value').then(function() {
return localforage.getItem('key');
}).then(function(value) {
// we got our value
}).catch(function(err) {
// we got an error
});
// async/await form
try {
const value = await localforage.getItem('somekey');
// This code runs once the value has been loaded from the offline store.
console.log(value);
} catch (err) {
// This code runs if there were any errors.
console.log(err);
}The library adds transaction handling to methods such as setItem and provides a LocalStorage‑like interface.
Multiple Instances
var store = localforage.createInstance({
name: "nameHere"
});
var otherStore = localforage.createInstance({
name: "otherName"
});
// Setting a key on one instance does not affect the other.
store.setItem("key", "value");
otherStore.setItem("key", "value2");Data Caching Practice
Video data fetched asynchronously can be stored in IndexedDB; a version identifier is saved with the data, and if the identifier changes the data is refreshed. This allows pre‑loading videos to avoid playback issues caused by network latency.
const loadVideo = async (url) => {
let res = await fetchVideoBlob(url);
return res;
}
export const getVideoData = async (videoKey) => {
const loadSrc = STORAGE_KEY[videoKey].src;
return localForage.getItem(STORAGE_KEY[videoKey].key).then(async function(value) {
if (value && value.src === loadSrc) {
// localForage successfully got item
const videoBlobUrl = URL.createObjectURL(value.data);
return videoBlobUrl;
} else {
// localForage failed to get item
const videoData = await loadVideo(loadSrc);
const storeData = {
src: loadSrc,
data: videoData
};
return localForage.setItem(STORAGE_KEY[videoKey].key, storeData).then(function(video) {
const videoBlobUrl = URL.createObjectURL(video.data);
return videoBlobUrl;
});
}
}).catch(err => {
throw new Error(`${videoKey} init error`);
});
}localForage does not create indexes; native IndexedDB APIs must be used for that purpose. Developers should also implement error handling, as localForage’s fallback to LocalStorage does not occur automatically when IndexedDB throws errors.
References
IndexedDB compatibility: https://caniuse.com/?search=indexDB
Web storage overview: https://web.dev/i18n/zh/storage-for-the-web/
Quota testing tool: https://storage-quota.glitch.me/
localForage API documentation: https://localforage.docschina.org/
IndexedDB Chinese tutorial: https://www.tangshuang.net/3735.html
LOFTER Tech Team
Technical sharing and discussion from NetEase LOFTER Tech Team
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.