An important step on the path toward robust, offline web applications is the ability to store data in the user’s browser. Technologies like IndexedDB and localStorage have provided this functionality to web developers, but they are not without their limitations.
The localStorage API is really simple to use, but you can only store text data. This limitation can generally be overcome by storing other types of data as JSON strings, but this can be a pain as you have to encode/decode JSON every time you need to store or retrieve some data. Not to mention you still have a problem if you need to store Blobs or files. LocalStorage is also a synchronous API, which means that your app could hang while data is being stored or retrieved.
IndexedDB, on the other hand, is an asynchronous API that includes great support for a wide range of data types, but the API itself is considerably more complex to use.
Enter localForage, a JavaScript library that provides the ease of use of localStorage with all the advanced features of IndexedDB.
Contents
An Introduction to localForage
The localForage JavaScript library was developed by the good folks at Mozilla to provide a simple storage API that has all the capabilities of more complex APIs like IndexedDB, but without the steep learning curve.
Behind the scenes, localForage uses native browser technologies like IndexedDB, WebSQL, and localStorage to actually store data. The localForage API sits on top of this datastore layer and provides a number of methods that can be used for managing data.
Note: WebSQL was dropped in favor of IndexedDB, but some browsers still include support for the WebSQL API.
The other main benefit of using localForage is that you don’t have to convert your data structures to JSON in order to save them in the datastore. If the underlying datastore technology (read: localStorage) doesn’t support the data type you provide, then localForage will take care of the JSON wizardry for you so you can just focus on building your app’s functionality.
Downloading the localForage Library
You can download a copy of localForage from the project’s home page.
Once you’ve downloaded the code archive, copy the localforage.js
file found in the dist
folder into your project. You can include this file in your web pages using a simple <script>
element.
<script src="/path/to/localforage.js"></script>
Licensing: localForage is released as free software under an Apache 2.0 license.
Storing Data
The localForage library will automatically set up a datastore using the best storage technology that’s available in the user’s browser.
As with localStorage, the data is stored using key/value pairs. The setItem
method is responsible for saving data in the datastore.
localforage.setItem('key', 'value', callbackFunction);
The value
here can be any kind of data you want: a string, number, object, or even a file.
If the key
already exists in the datastore, the existing value
will simple be overwritten.
Unlike with localStorage, the localForage API is asynchronous and therefore you shouldn’t expect the setItem
method to return a value. Instead, you can pass a callback function to the setItem
method. This callback function will be executed once the data has been stored and will be passed the value
that was saved in the datastore.
Note: The amount of storage space accessible to localForage is governed by the underlying datastore technology that’s being used. For localStorage, the general limit is 5MB, although this may vary among browsers. More space is available when IndexedDB is being used, but the user may be prompted to approve additional quota if your app needs to store large amounts of data.
Retrieving Data
Data can be retrieved from the datastore using the getItem
method. You should pass in the key
of the item you wish to retrieve, as well as a callback function that will be passed the value
for the item.
localforage.getItem('key', callbackFunction);
If the specified key
doesn’t exist in the datastore, the callback function will be passed null
.
Deleting Data
If you want to delete some data, you can use the removeItem
method. Pass in the key
of the item you wish to delete and a callback function.
localforage.removeItem('key', callbackFunction);
Clearing The Datastore
You can remove all the data from the datastore using the clear
method.
localforage.clear(callbackFunction);
Again, this method can be passed a callback function that will be executed when the operation has completed.
Requesting The Number of Keys in The Datastore
The length
method can be used to retrieve the number of items that are currently in the datastore.
localforage.length(callback);
Finding a Key in The Datastore
The localForage API also includes a method that can be used to retrieve a key
based on its position within the datastore.
localforage.key(n, callback);
This method is particularly useful if you need to loop over each of the items in the datastore. For example:
// Find the number of items in the datastore.
localforage.length(function(length) {
// Loop over each of the items.
for (var i = 0; i < length; i++) {
// Get the key.
localforage.key(i, function(key) {
// Retrieve the data.
localforage.getItem(key, handleData);
});
}
});
localForage Supports Promises!
So far in this post I’ve shown that each of the methods in the localForage API can be passed a callback function. I’ve used these in the traditional manner of adding the callback function as a parameter in the method call. However, there is an alternative.
The localForage API includes support for ECMAScript 6 Promises, which provide a better way of handling asynchronous code. (If you’re not comfortable with using Promises, feel free to pretend this section doesn’t exist.)
Here’s an example of how you can use Promises rather than callbacks when retrieving an item from the datastore.
localforage.getItem('key').then(function(value) {
console.log(value);
});
Browser Support
The localForage library will work in all modern web browsers. Some older browser versions may not support IndexedDB or WebSQL, in which case the library will use localStorage instead. This means that calls to the API will be executed synchronously in these browsers.
IE | Firefox | Chrome | Safari | Opera |
---|---|---|---|---|
10 | 10 | 23 | 3.1 | 15 |
The localForage library also has great support for mobile browsers.
Android Browser | Blackberry | Chrome for Android | Firefox for Android | Firefox OS | IE Mobile | Safari | Opera Mobile |
---|---|---|---|---|---|---|---|
2.1 | 7 | 32 | 25 | 1 | 10 | 3.1 | 11 |
Source: https://github.com/mozilla/localForage#supported-browsersplatforms
Summary
By providing an easy-to-use API that abstracts away the complexity of other storage technologies like IndexedDB, localForage has become a compelling storage solution for building offline web applications. It’s certainly something that I’ll be looking to use in future projects.
What do you think about localForage? Share your thoughts in the comments below.
Hi,
Local forage performance is far more worse then local srtorage. We we angularjs application we are caching our api call responce in local storage. To improve the performance I tried local forage with indexedDB but read time is too slow with indexed db. Is there a way to achieve fast reading and writing with local storage?
LocalForage doesn’t work well with any IE under 11.
The lack of support for promises, (even in the no-promises version of localForage) causes headaches trying to get it working on anything under IE11. I swapped to store.js instead, much smoother sailing.
A very good read. Understood the concept with clarity. Thanks a lot!
Can localForage Supports FileAPI for reading and writing?
Good article.
I have one question here. If a browser is not compatible with WebSQL and IndexedDB, What is the maximum storage it can support? is it 5 MB for Local Storage?
How do you mock localForage in your tests? Let’s say there’s a need to mock localForage.getItem and return ‘value’. I initially tried to mock the promise but it didn’t work:
beforeEach(function(){
spyOn($localForage, ‘getItem’).and.returnValue($q.when(‘value’));
}
Before this I use ngStorage – https://github.com/gsklee/ngStorage. I found that this localForage is good too. Looking forward to use it in my next project. Thanks!
Interesting read, thanks for sharing, I might give it a try this weekend 🙂
Do any of these provide any additional security? My understanding is that, right now, any Javascript has automatic access to all the localStorage associated with that page, whether it be set from the same script or not. Seems like it should be used with caution.
Not that I’m aware of. The datastores are sandboxed to the domain so any JavaScript that runs on the site can access the data.
I see the security concern here but you probably shouldn’t be using client-side storage for sensitive data anyway. If you’re building a purely offline web app the risk of having a malicious script access the data is somewhat reduced.
You could look into JavaScript encryption methods for protecting data (https://code.google.com/p/crypto-js/) but this is probably overkill.