4+1 Ways To Store Data In The Web Browser

4+1 Ways To Store Data In The Web Browser

·

14 min read

As the popularity of Single-Page-Application(SPA) rises, the need to store data locally on the client-side becomes increasingly common.

Today, we will examine 4 different methods to store data in a web browser along with basic code examples. We will also touch on an upcoming new storage API that is currently in the experimental stage.

Introduction

As web applications become increasingly complex, more sophisticated methods to store data locally on the client-side is needed to match with the capabilities of the multitude of server-side storage options available.

Storing data locally also enables offline capability in a web application that helps deliver a smoother user experience for your users even when under poor network condition.

Let's look at the different storage options available in a modern web browser.

1. Cookies

The most common purpose of storing data locally in web browsers is to retain user session. This has been faithfully served by the use of Cookies ever since the introduction of the Mosaic Netscape browser released in 1994.

To set a cookie, a server needs to return the Set-Cookie in the HTTP response headers as such:

HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: app_session=abcde12345

Most server-side languages have specific methods to do so. For example, in PHP you could call the setcookie() method:

<?php
setcookie("app_session", "abcde12345");
// must be set before any other output
...

The cookie will then get sent back to the server that matches the domain in subsequent requests to the server.

To retrieve the cookies on the frontend, you can access them with the following JavaScript property:

document.cookie
// will return "app_session=abcde12345;"

❗️ Only cookies that are not set with the HttpOnly option is accessible via code on the client-side browser.

You can also use the same property to set a cookie from the browser:

document.cookie = "session_id=abcde12345";

❗️ Please note that multiple cookies with the same name can exist for the same domain path. Your application must be able to determine which value to use.

However, a cookie can only hold a limited amount of data. In fact, you can only store up to 4096 bytes of data in a cookie. Not to mention cookies come with an expiration date, just like the Christmas cookies from last year that you are still keeping in your jar.

Cookies also get sent back to the domain server in every request, which may not be necessary for certain types of web applications.

2. localStorage

That's when localStorage comes to the picture. localStorage provides none of the limitations of a cookie stated above, while at the same time able to persist the data even when the browser was restarted.

With localStorage, you can store up to 5MB of data in Google Chrome, and they will never expire unless explicitly cleared by the user or through JavaScript code.

You may also be able to save on bandwidth as localStorage does not send its data to the server in every request.

Here's how you can store data into localStorage using JavaScript:

localStorage.setItem('product_id', 25);

You may close the browser window and the data will still persist in the localStorage.

To retrieve the data, simply run the following JavaScript code:

localStorage.getItem('product_id')
// will return "25"

All data save to localStorage will be converted into Strings. Therefore, if you want to store objects, you can use JSON to do so:

localStorage.setItem('person', JSON.stringify({ name: 'John' }));
// will be converted into strings as "{"name":"John"}"

To read the object data, just parse the returned string with JSON again:

JSON.parse(localStorage.getItem('person'))
// returns a proper Object type

You may also perform other operations to the data easily through the following methods:

localStorage.removeItem('product_id')
// remove an item by key

localStorage.clear()
// remove all data

localStorage data are bound to the current domain, protocol, and port. So, data between different domain's localStorage space will not interfere with each other.

This also means that if a user has another tab or window opened with the same domain origin, both can read the same data in the domain's localStorage. This shared property is useful in applications where you need to ensure data integrity across all active app instances.

However, if you do not want data to retain after the browser window is closed or to share data across other opened windows, you may consider using sessionStorage instead.

3. sessionStorage

sessionStorage has the same properties and methods with localStorage, but it's limited in two ways.

The first is that the data stored in sessionStorage will only survive a page refresh, but will be gone if the window is closed.

As the name implies, sessionStorage is more useful for application where data is only needed to be retained throughout the current browser session.

The second limitation of sessionStorage is that the data are only available to the current window, and it's not available to another tab or window opened even with the same domain origin.

This is useful in cases where you want your user to have a fresh session every time they load your application site.

4. IndexedDB

If you require a storage solution that is more closely resembles a database, you may consider using the IndexedDB storage.

With IndexedDB, you can store more than just strings and plain text in a much bigger storage size limit. We are talking about up to 60% of the device's available space. Therefore, storing a few hundred megabytes of data is possible.

IndexedDB even supports transaction, queries, auto-increment, and indexes, just like a database engine that is commonly used on the server-side.

With such powerful capabilities, IndexedDB is best used for building offline web applications that are typically used together with ServiceWorkers.

Let's look at some code on how to store data into IndexedDB.

i) Open a Connection

Just like a typical database, before we can insert any data, we need to open a connection to it:

// the syntax is indexedDB.open(name, version);
let openRequest = indexedDB.open('myLocalDb', 1);

Similar to other Web Storage methods mentioned earlier, the database will exist within the current origin domain, protocol, and port. But as you can guess from the code above, you can have many databases within an origin. All you need to do is open a new IndexedDB connection with a different name.

The openRequest is now an object and will emit onsuccess, onerror, and onupgradeneeded events to be listened to subsequently.

The onupgradeneeded will only be triggered if the database has not been created before, or a new version number is introduced.

ii) Create an Object Store

Next, let's create a table or collection. In IndexedDB, this is called an Object Store, which can only be created in the onupgradeneeded event handler:

openRequest.onupgradeneeded = function() {
    let db = openRequest.result;

    // the syntax is createObjectStore(name[, keyOptions]);
    db.createObjectStore('fruits', {keyPath: 'id'});
    // keyPath is the object property that IndexedDB will use as the key for query later
};

This makes sense because you don't want to keep running the object store creation script every time your application is launched.

If you want to create or modify an object store, you will have to change the version number when opening a new IndexedDB connection.

iii) Storing Data

Once our object store is available, we can now store some data into it within the onsuccess handler:

openRequest.onsuccess = function() {
    let db = openRequest.result;

    // prepare the transaction
    let transaction = db.transaction('fruits', 'readwrite');
    // 'readwrite' means we want to perform a write operation

    // prepare the object store for use
    let fruits = transaction.objectStore('fruits');

    // our data to be stored. Any data type is possible
    let banana = {
        id: 'banana',
        price: 12,
        created: new Date()
    };

    // add the data into the object store
    let request = fruits.add(banana);

    request.onsuccess = function() {
        console.log("Fruit added successfully", request.result);
    };

    request.onerror = function() {
        console.log("Error: ", request.error);
    };
};

iv) Retrieving Data

To retrieve our data, just call the get() method on the object store as such:

openRequest.onsuccess = function() {
    let db = openRequest.result;

    // prepare the transaction
    let transaction = db.transaction('fruits', 'readonly');
    // 'readonly' indicates we only want to retrieve data

    // prepare the object store for use
    let fruits = transaction.objectStore('fruits');

    // get the data by the id keyPath
    let request = fruits.get('banana');

    request.onsuccess = function() {
        console.log("Fruit: ", request.result);
    };

    request.onerror = function() {
        console.log("Error: ", request.error);
    };
};

v) Deleting Data

To remove data from the object store, we can use the delete() method:

openRequest.onsuccess = function() {
    ...
    // similar code as before
    let transaction = db.transaction('fruits', 'readwrite');
    // here we need to specify 'readwrite' because we are modifying data

    // delete data by keyPath
    fruits.delete('banana');
    ...

    // or delete ALL data in the Object Store
    fruits.clear();
};

There are many more methods and techniques in using IndexedDB. If you would like to learn more, be sure to check out the links under the Resources section at the bottom.

5. Cache API

The Cache API is a new storage mechanism that is designed for storing HTTP responses to specific requests that is also commonly used in conjunction with ServiceWorker.

According to MDN, this API is currently under experimental phase. So, it is not recommended to be used in your serious project for now.

However, as a web developer, it's always good to be aware of new tools that are available at our disposal. You may read about it further by checking out the links below.

🎁 Bonus: Viewing Local Storage Data

As a last tip, while developing your application with local storage, you can always view all the data easily from your browser DevTools.

In Chrome, just press F12 and navigate to Application tab:

Screenshot 2020-12-20 at 9.37.12 PM.png

You may ignore the Web SQL data store as it is no longer under active development since 2010

From here, you can easily browse through all the data in your local store under the current domain. It is also possible to edit and remove the data manually which makes testing your application very convenient.

🏁 Summary

We have covered all the important local storage options available in most major web browsers.

Each storage methods have different traits that are useful in certain applications. You can always pick the one that best fits your requirements.

🙏 Thank you for reading! I hope you learnt as much as I did. 🚀 If you find this article useful, please share it with your followers. 🦊

📚 Resources