When you need to store more complex data on your browser, Web Storage API may not be the best solution. It has some limitations and isn't specifically designed for complex data. Given these limitations, you might prefer a more effective option because complex data takes up more storage space, especially when working with larger amounts of it. At this point, IndexedDB steps in as a genuine client-side database. That means, it effectively handles larger amounts of data and more complex data structures, all while running locally on your browser.
IndexedDB in action
Imagine this: You've just started writing an important paper on Google Docs. You're really focused and making great progress. But guess what? Right after you start typing, your internet connection drops! And, here comes the surprising part: even though you've lost internet, you can keep working on your document. Besides, at the top of the app's interface, you see a small message that says 'Saved to this device'. Your work is still being saved! How is that even possible?
In fact, it's not magic, but rather a special system used in web technology known as IndexedDB. This API allows both web pages and web applications, such as Google Docs, to store information in your browser. This means that even when you're offline, you can still access and edit your documents. Any changes you make are saved locally in your browser, all thanks to IndexedDB.
IndexedDB works by creating a database in the browser. When you visit dynamic webpages, such as Amazon, or web applications like Google Docs, these sites take on this job. But, if you want to build an app offline with JavaScript, you can create your own database, and even manage this database on your browser, just like websites using IndexedDB do.
Why IndexedDB?
Like localStorage and sessionStorage, IndexedDB also saves data in your browser. If they all serve the same purpose and are similar in some ways, what makes IndexedDB stand out from the others?
IndexedDB keeps data even if you close your browser as localStorage does, but sessionStorage doesn't do it — it gets rid of data when you close the browser. Also, IndexedDB can store a lot more data than localStorage or sessionStorage. It can use up to half the space on your hard drive. However, Local Storage and Session Storage can only use 5-10 MB.
IndexedDB also uses key-value pairs to store data, just like Local Storage and Session Storage. The big difference is that while Local Storage and Session Storage can only store data in string format, IndexedDB can also store other data types like objects, arrays, and even media files.
Using developer tools with IndexedDB
As you remember from earlier topics, we use developer tools in our browser to manage cookies and the data stored by APIs like localStorage and sessionStorage. In the same way, these tools also allow us to check the state of IndexedDB. When you open the DevTools, go to the 'Application' panel, and expand the IndexedDB menu, you can see the databases created by the current web page. If you click on a listed database, you can also view the objects stored in each one. For example, the image below displays the databases created by Google Docs on a browser, along with related information about them.
When you click on a database here, you can see more items inside. These are known as object stores. You can think of an object store as a sub-storage, similar to a drawer in a file cabinet. A single object store in a database can contain different types of information or objects, and every object within the object stores has a unique key. In the simplest terms, this is how IndexedDB stores and organizes data for websites and web apps.
If we go around the databases on our Google Docs browser page and open up the database named 'Google Docs', we can see a number of object stores listed there. When we click on the object store named 'FontMetaData', as shown in the image above, we can see the unique keys for font families along with their associated data.
Objects and methods in IndexedDB
indexedDBobject
To interact with IndexedDB, we use the global indexedDB. This object can be accessed in our browser's console with window.indexedDB or simply indexedDB. When using indexedDB as the main object, we typically pair it with other methods to perform various tasks within IndexedDB.
For example, you can check whether your browser supports IndexedDB using the following if-else conditional lines of code on the console:
if (!('indexedDB' in window)) {
console.log('This browser does not support IndexedDB');
} else {
console.log('This browser supports IndexedDB');
}
If your browser does support IndexedDB, as most modern browsers do, the console will output This browser supports IndexedDB.
Now, let's return to our example of the console on the Google Docs web app page. When we enter window.indexedDB to access IndexedDB on our console, we'll see something like this:
In the image above, when we access window.indexedDB on our console, we see a list that begins with IDBFactory {}. This object can be thought of as the master control panel for IndexedDB. Using IDBFactory, you can do several tasks like comparing keys with cmp, getting a list of all your databases with databases, deleting a database entirely with deleteDatabase, and creating a new database with a specific name and version with open. Let's take a closer look at how these methods work in IndexedDB API.
open()method
When you call the open method to create or open a database in IndexedDB, you pass two arguments: the database name and the version number. The version number is essential for managing the database's structure and keeping track of changes over time.
let myRequest = indexedDB.open('myDatabase', 1)
After adding this line to the console, you should go to the browser's 'Application' panel in the developer tools, and check if your database has been created in the IndexedDB section. You should see it there, as shown in the image below. If you don't see the database, you can try refreshing the page.
databases()method
When you type indexedDB.databases() in the console, it returns Promise with a message saying it's waiting for the list of databases. Once it gets the list, PromiseState becomes "fulfilled", and you'll see the details of the databases.
Again, when we go back to the same Google Docs web app page and use indexedDB.databases() in the console, we see four listed databases: DocsErrors, GoogleDocs, GoogleDriveDs, and myDatabase, which is the database we created. It's important to know that these databases, except myDatabase, belong to a third-party app, like the Google Docs web application, and you cannot access or modify them from the client side (like using JavaScript code directly in the browser) without proper authorization. Trying to do so without permission is not allowed.
cmp()method
In IndexedDB, each key you use to save data must be unique. If you try to save data using a key that's already in use, it won't work. To avoid this problem, it is important to check if a key is already used before saving.
At this point, the cmp() method in IndexedDB helps us compare two keys in the database, and it uses a system called lexicographical order to do that. Imagine it as placing all characters, like the letters A to Z, in a certain order. This is similar to alphabetical order, but it works with all characters, not only letters. Instead of dictionaries, computers use encoding systems like ASCII or Unicode to decide this order, assigning each character a unique number.
Based on the comparison of two keys (which can be strings or numbers), cmp() method returns -1, 0, or 1. Here's when each value is returned:
- -1: The first key is lexicographically smaller than the second key.
- 0: The two keys are lexicographically equal.
- 1: The first key is lexicographically greater than the second key.
Let's take a closer look at the following comparison cases:
let key1 = 'Shrek';
let key2 = 'Fiona';
let comparisonResult1 = indexedDB.cmp(key1, key2);
console.log(comparisonResult1); // Output: -1
let key3 = 'Shrek';
let key4 = 'Shrek';
let comparisonResult2 = indexedDB.cmp(key3, key4);
console.log(comparisonResult2); // Output: 0
let key5 = 'Fiona';
let key6 = 'Shrek';
let comparisonResult3 = indexedDB.cmp(key5, key6);
console.log(comparisonResult3); // Output: 1
When comparing 'Shrek' with 'Fiona', the cmp method returns -1 because 'Shrek' comes before 'Fiona' in alphabetical order. Comparing two identical keys, like 'Shrek' and 'Shrek' returns 0 since they are the same. On the other hand, when comparing 'Fiona' with 'Shrek', the method returns 1 because 'Fiona' comes after 'Shrek' in alphabetical order.
deleteDatabase()method
Lastly, when you want to delete a database you've created, you can use deleteDatabase(). You can pass the name of the database you want to delete as an argument to this method, as in the example below.
let deleteRequest = indexedDB.deleteDatabase('myDatabase')
After you type this code in the console and refresh the page, you'll see the database you made is now gone from the IndexedDB menu.
Conclusion:
IndexedDB is a database system that is capable of saving more data in your browser compared to other Web Storage APIs, like localStorage and sessionStorage. Besides storing more data, IndexedDB can also save different types of data such as objects, arrays, and even media files. To organize and handle that amount and type of data, it uses object stores, and each piece of data in these object stores has a unique key.
Although we have looked at simple tasks with IndexedDB, like opening and deleting a database or comparing keys, it's important to note that using IndexedDB in the console can be limited due to a browser's security protocols. It's usually used within a webpage or app rather than working on the console.
Despite these limitations, there's a lot more you can do with IndexedDB, like managing and storing lots of data. Working with local files can help overcome some of these restrictions and provide a better environment for learning and experimenting. If you want to learn about more advanced things like adding or changing data, you can check out the IndexedDB guide on the MDN website.