localForage is a fast and simple asynchronous JavaScript library for persisting key-value pairs in the browser’s localStorage, IndexedDB, and WebSQL. It provides a unified API across these different storage mechanisms, abstracting away the complexities of managing each individually. This allows developers to write code that works consistently across various browsers and devices, without needing to worry about the underlying storage technology. localForage automatically determines the best available storage mechanism for the user’s browser and gracefully falls back to others if necessary.
localForage supports most modern browsers, including:
While it primarily targets browsers, it can also be used in Node.js environments with the appropriate adapter. However, direct Node.js support is not a core feature; using it would require a suitable adapter/shim for filesystem or similar storage.
localForage can be installed using npm or yarn:
npm install localforage
# or
yarn add localforage
For use in a browser environment without a package manager, you can include the library via a <script>
tag. Download the minified version from the project’s distribution and include it in your HTML file:
<script src="path/to/localforage.min.js"></script>
After installation, you can start using the localForage API in your JavaScript code.
setItem(key, value)
Stores a value associated with a given key. The key must be a string. The value can be any valid JavaScript data type, though complex objects will be serialized (typically using JSON.stringify). The method returns a Promise that resolves when the operation is complete. It rejects with an error if the operation fails (e.g., due to storage limitations or quota issues).
.setItem('myKey', 'myValue').then(() => {
localforageconsole.log('Value stored successfully!');
.catch(err => {
})console.error('Error storing value:', err);
; })
getItem(key)
Retrieves the value associated with a given key. The key must be a string. The method returns a Promise that resolves with the stored value. If the key doesn’t exist, it resolves with null
. It rejects with an error if the operation fails.
.getItem('myKey').then(value => {
localforageconsole.log('Retrieved value:', value);
.catch(err => {
})console.error('Error retrieving value:', err);
; })
removeItem(key)
Removes the value associated with a given key. The key must be a string. The method returns a Promise that resolves when the operation is complete. It rejects with an error if the operation fails (e.g., the key doesn’t exist).
.removeItem('myKey').then(() => {
localforageconsole.log('Value removed successfully!');
.catch(err => {
})console.error('Error removing value:', err);
; })
clear()
Removes all key-value pairs from the storage. Returns a Promise that resolves when the operation is complete and rejects if an error occurs.
.clear().then(() => {
localforageconsole.log('Storage cleared successfully!');
.catch(err => {
})console.error('Error clearing storage:', err);
; })
key(n)
Returns the nth key in the storage. n
is a zero-based index. Returns a Promise that resolves with the key (as a string) at the specified index or null
if the index is out of bounds. It rejects with an error if an error occurs during the operation.
.key(0).then(key => {
localforageconsole.log('First key:', key);
.catch(err => {
})console.error('Error getting key:', err);
; })
length()
Returns the number of key-value pairs in the storage. Returns a Promise that resolves with the number of items. Rejects with an error if an error occurs.
.length().then(length => {
localforageconsole.log('Number of items:', length);
.catch(err => {
})console.error('Error getting length:', err);
; })
iterate(callback)
Iterates over each key-value pair in the storage, calling the provided callback function for each one. The callback function receives the value and the key as arguments. The method returns a Promise that resolves when all items have been iterated, or rejects if an error occurs.
.iterate((value, key) => {
localforageconsole.log('Key:', key, ', Value:', value);
.then(() => {
})console.log('Iteration complete');
.catch(err => {
})console.error('Error during iteration:', err);
; })
keys()
Returns a Promise that resolves with an array of all keys in the storage. Rejects with an error if an error occurs.
.keys().then(keys => {
localforageconsole.log('All keys:', keys);
.catch(err => {
})console.error('Error getting keys:', err);
; })
localForage prioritizes IndexedDB, falling back to WebSQL (deprecated) and then localStorage. You can explicitly specify a driver if needed, though this is generally unnecessary. To force a specific driver, use the localforage.setDriver()
method before any other localForage operations. The available drivers are: localforage.LOCALSTORAGE
, localforage.INDEXEDDB
, and localforage.WEBSQL
.
// Force the use of localStorage
.setDriver(localforage.LOCALSTORAGE).then(() => {
localforage// Your localForage operations here
.catch(err => {
})console.error('Error setting driver:', err);
; })
Note that forcing a specific driver might lead to reduced functionality or performance if that driver isn’t supported or suitable for the data being stored.
While automatic driver selection is usually sufficient, you can fine-tune the behavior of individual drivers. This is particularly useful for IndexedDB where you can customize database name and version. Configuration is done through the config
option when initializing localForage (or using localforage.config()
before any other operations).
.config({
localforagename: 'myDatabase', // IndexedDB database name
version: 1, // IndexedDB database version
storeName: 'keyvaluepairs', // IndexedDB store name
description: 'My localForage database' // IndexedDB database description (optional)
.then(function() {
})// Your code here
; })
Refer to the localForage documentation for the complete list of configurable options for each driver. Incorrect configuration can lead to errors.
All localForage methods return Promises, allowing for robust error handling using .catch()
. Errors can occur due to various reasons, such as storage quota limitations, browser restrictions, or driver-specific issues. Always include error handling in your code to gracefully handle potential failures.
.setItem('myKey', 'myValue').then(() => {
localforage// Success
.catch(err => {
})console.error('Error:', err); // Handle error appropriately
// For example, display a user-friendly error message, retry, or fallback to alternative storage.
; })
localForage utilizes Promises extensively for all its operations. This ensures that your application remains responsive, preventing blocking while waiting for storage operations to complete. Always use .then()
to handle successful operations and .catch()
for error handling. Avoid using .done()
which is deprecated.
For multiple setItem
calls, consider using a single Promise.all to improve performance. This reduces the overhead of multiple asynchronous calls.
const promises = [
.setItem('key1', 'value1'),
localforage.setItem('key2', 'value2'),
localforage.setItem('key3', 'value3')
localforage;
]
Promise.all(promises)
.then(() => console.log('All items set'))
.catch(error => console.error('Error setting items:', error));
localForage relies on the browser’s built-in storage mechanisms. If storage space is limited, exceeding the quota will result in errors. To manage storage space:
localforage.removeItem()
or localforage.clear()
to remove data that’s no longer needed.For optimal performance:
Promise.all
for multiple simultaneous operations.Migrating from other storage solutions involves extracting data from the old system and importing it into localForage. The exact steps depend on the source storage solution but generally include:
localforage.setItem()
to insert the transformed data into localForage.This example demonstrates basic key-value storage using setItem
and getItem
.
.setItem('username', 'john_doe').then(() => {
localforage.getItem('username').then(username => {
localforageconsole.log('Username:', username); // Output: Username: john_doe
;
}); })
This stores the string “john_doe” under the key “username” and then retrieves it. Error handling should be added for production use.
localForage handles complex data structures by serializing them using JSON.stringify. Ensure that your data is serializable before storing it.
const user = {
name: 'Jane Doe',
email: 'jane.doe@example.com',
age: 30
;
}
.setItem('user', user).then(() => {
localforage.getItem('user').then(retrievedUser => {
localforageconsole.log('Retrieved User:', retrievedUser); // Output: Retrieved User: {name: "Jane Doe", email: "jane.doe@example.com", age: 30}
;
}); })
Note that the retrieved retrievedUser
will be a JavaScript object, not a JSON string.
localForage is well-suited for caching data fetched from a remote server. Store fetched data with a key representing the data’s source and update/remove it as appropriate.
function fetchData(url) {
return fetch(url)
.then(response => response.json())
.then(data => {
.setItem('cachedData-' + url, data);
localforagereturn data;
;
})
}
function getCachedData(url) {
return localforage.getItem('cachedData-' + url)
.then(data => data || fetchData(url)); // Fetch if not cached
}
getCachedData('/api/users')
.then(data => console.log('Users:', data));
This example checks for cached data before making a network request.
Offline-first applications rely on local storage to provide functionality even without an internet connection. localForage enables this by allowing you to store application data locally and synchronize it with a server when connectivity is restored.
// Store data locally when creating a new item.
function createItem(item) {
.setItem('item-' + item.id, item).then(() => {
localforage// Optionally, queue the item for synchronization with a server.
;
})
}
// Load data on application startup.
.keys().then(keys => {
localforageconst promises = keys.map(key => localforage.getItem(key));
Promise.all(promises).then(items => {
// Process items and update the UI.
;
}); })
This showcases storing items locally, loading them at startup, and suggesting a mechanism to synchronize with a server later.
localForage integrates well with other JavaScript libraries. You can use it in conjunction with frameworks like React, Angular, Vue.js, and others. It also pairs well with libraries for handling data synchronization or background tasks. The integration usually involves using localForage’s API within the context of the other library’s methods and lifecycle. For example, you might use localForage to persist application state in a React application within a component’s useEffect
hook or store data used by a Vue.js application within a Vuex store. No special integration code is typically required; you simply use localForage API calls within your existing application code.
localForage itself does not provide encryption or any specific mechanisms for protecting data at rest. The security of data stored using localForage depends entirely on the browser’s security model and the security of the overall application. Sensitive data should never be stored directly using localForage without appropriate encryption. Consider using a library that provides encryption capabilities before storing sensitive data (e.g., encrypting the data before storing it in localForage and decrypting it upon retrieval). The responsibility for securing sensitive data rests entirely with the application developer. The browser’s storage mechanisms (localStorage, IndexedDB) are subject to the same security implications as other browser-based storage mechanisms.
CORS is not directly relevant to localForage because it operates within the context of a single origin (the website or application that’s using it). localForage only interacts with the browser’s storage mechanisms available to that origin. Data stored in localForage using one origin is not accessible to scripts from a different origin. This inherent browser-level security prevents cross-origin access.
Cross-Site Scripting (XSS) attacks are a significant web security risk. localForage itself does not directly prevent XSS attacks; rather, secure coding practices are crucial. XSS vulnerabilities arise from improperly handling user-supplied data. When using localForage, ensure that you sanitize and escape any user-provided input before storing it. Never directly insert user-supplied data into keys or values in localForage without appropriate validation and sanitization. Improper handling of data could allow an attacker to inject malicious scripts into your application’s data, potentially leading to compromised user data or other harmful consequences. Use a robust input validation and sanitization library to mitigate the risk of XSS vulnerabilities within the broader application context, including data handled by localForage.
We welcome contributions to localForage! Whether it’s fixing bugs, adding features, or improving documentation, your help is valuable. Here’s how to get started:
Clone the repository: Clone the localForage repository from GitHub:
git clone https://github.com/localForage/localForage.git
Install dependencies: Navigate to the project directory and install the necessary packages using npm or yarn:
npm install
# or
yarn install
Run the development server (optional): A development server is usually available (check the project’s README) to aid in development and testing. Start it using the appropriate command. This might involve a command like npm start
or yarn start
.
Follow the existing coding style in the project. Consistency is key. Pay attention to:
Refer to any existing style guides (e.g., a .editorconfig
file or a CONTRIBUTING.md file) within the repository for more specific guidelines.
localForage has a comprehensive test suite. Before submitting a pull request, ensure that your changes don’t introduce regressions. Run the tests using the commands specified in the project’s README file. This typically involves using a command such as npm test
or yarn test
. The test suite often covers different browsers and edge cases. Addressing any test failures is crucial before merging your code.
Create a branch: Create a new branch for your changes:
git checkout -b my-feature
Make your changes: Implement your changes, ensuring code quality and thorough testing.
Commit your changes: Write clear and concise commit messages explaining your changes.
git add .
git commit -m "Fix: Resolved issue #123"
Push your branch: Push your branch to the remote repository:
git push origin my-feature
Create a pull request: Create a pull request on GitHub, clearly describing the changes you made and addressing any relevant issues. Provide a clear explanation of the problem you’re solving and how your changes address it. Also, mention any specific test cases that were added or modified. The maintainers may request changes; address these promptly and push updated commits to your branch.
Remember to follow the project’s contribution guidelines (if any) for more specific instructions.
What is the difference between localForage and localStorage? localForage provides a unified API across multiple storage mechanisms (localStorage, IndexedDB, WebSQL), offers better performance for larger datasets, and handles asynchronous operations gracefully. localStorage is simpler but has limitations in size and asynchronous operation handling.
Why are my operations failing? Check your error handling. Common causes include exceeding storage quotas, browser restrictions, and incorrect driver configuration. Consult the browser’s developer console for detailed error messages.
How can I migrate from localStorage to localForage? Extract data from localStorage, convert it to a suitable format (like JSON), and then use localforage.setItem()
to import it into localForage.
Does localForage support encryption? No, localForage does not provide built-in encryption. You’ll need to encrypt data before storing it and decrypt it upon retrieval using a separate encryption library.
Which driver should I use? localForage automatically selects the best driver. Forcing a specific driver is generally unnecessary unless you have specific requirements or need to handle unsupported drivers.
Release notes would typically be found in a separate file or section on the project’s website or repository. They detail changes, bug fixes, and new features in each release version of localForage.
localForage is typically licensed under either the MIT License or a similar permissive open-source license. Refer to the LICENSE file in the project’s repository for the exact terms and conditions of the license.