JavaScript IndexedDB

IndexedDB is a powerful, client-side storage API that is more robust than other local storage solutions available in web browsers. It allows for significant amounts of structured data to be stored and manipulated asynchronously by web applications. IndexedDB is perfect for applications that require offline data storage, high performance, and rich query capabilities without reliance on a network connection.

Setting Up an IndexedDB Database

Step 1: Open a Database

To use IndexedDB, the first step is to open a database. Here is how you can create or open an IndexedDB database. Also after successful operation, we are closing and deleting the database to prevent unwanted side-effects on other examples you will run. You may skip this step in your own codes, or include it if you need.

const request = window.indexedDB.open('MyTestDatabase'); request.onerror = function(event) { console.error('Database error: ' + event.target.errorCode); }; request.onsuccess = function(event) { console.log('Database opened successfully.'); // close const db = event.target.result; db.close(); // delete window.indexedDB.deleteDatabase('MyTestDatabase'); console.log("Database closed and deleted"); };

Step 2: Creating Object Stores

Once the database is opened, you can proceed to create an object store which is akin to a table in relational databases. It's important to notice, however, that this can only be done when a new version of db is published. It means, it's either the first publishment, or when you open the db again but with another version number. The event to listen for it, is the onupgradeneeded.

const request = window.indexedDB.open('MyTestDatabase'); request.onupgradeneeded = function(event) { const db = event.target.result; const store = db.createObjectStore('Books', {keyPath: 'id'}); console.log('Object store created'); db.close(); window.indexedDB.deleteDatabase('MyTestDatabase'); console.log("Database closed and deleted"); };

Transactions

A transaction in IndexedDB is a mechanism that groups multiple operations into a single unit of work that either completely succeeds or completely fails. It is essential for ensuring data consistency and integrity, especially when multiple operations depend on each other to produce a correct outcome.

How to Use Transactions in IndexedDB

Step 1: Starting a Transaction

To perform any operation in IndexedDB, you start by creating a transaction on a database. A transaction is created by specifying which object stores the transaction will involve and the mode of the transaction, which can be either "readonly" or "readwrite".

Step 2: Accessing an Object Store

Within a transaction, you can access one or more object stores to perform data operations.

Step 3: Performing Operations

Once you have access to an object store, you can execute various operations like adding, retrieving, updating, or deleting data. Each operation returns a request object that you can use to handle success or error events.

Step 4: Completing the Transaction

A transaction will automatically complete once all the operations issued in it have been resolved, either by succeeding or failing. You can also listen for the complete event on the transaction to perform actions after all operations have successfully finished.

Here is an example of a complete transaction:
// Step 1: Open the IndexedDB database let db; const DB_NAME = 'TestDB'; const request = indexedDB.open(DB_NAME); request.onerror = function(event) { console.error('Database error:', event.target.errorCode); }; request.onupgradeneeded = function(event) { db = event.target.result; if (!db.objectStoreNames.contains('Books')) { db.createObjectStore('Books', { keyPath: 'id' }); } }; const clean = function() { db.close(); window.indexedDB.deleteDatabase(DB_NAME); console.log("Database closed and deleted"); } request.onsuccess = function(event) { db = event.target.result; // Step 2: Start a transaction const transaction = db.transaction(['Books'], 'readwrite'); // Access the object store const store = transaction.objectStore('Books'); // Step 3: Perform operations - Adding a new book const book = {id: 1, title: 'Effective JavaScript', author: 'David Herman'}; const addRequest = store.add(book); addRequest.onsuccess = function() { console.log('Book added successfully!'); }; addRequest.onerror = function(event) { console.error('Failed to add book:', event.target.error); }; // Step 4: Complete the transaction transaction.oncomplete = function() { console.log('Transaction completed successfully.'); clean(); }; transaction.onerror = function() { console.error('Transaction failed.'); clean(); }; };

How to view IndexedDB content in your browser

Most modern browsers show you what is stored in the IndexedDB. Below is the example from Chrome's developer tools:

IndexedDB

Best Practices for Using Transactions

  1. Minimize the Scope: Keep transactions as small as possible, both in terms of the number of operations and the duration. This reduces the likelihood of conflicts and improves performance.

  2. Error Handling: Always implement error handling on both the request and transaction levels. This helps in diagnosing issues and preventing partial updates that could lead to data corruption.

  3. Concurrency: Understand that while IndexedDB is asynchronous and non-blocking, transactions on the same database are queued and executed serially to prevent data races and inconsistencies.

Conclusion

IndexedDB provides a robust platform for complex data management in web applications, making it an essential tool for modern web developers. Through the proper implementation of its features, developers can efficiently store, retrieve, update, and delete client-side data, enhancing application performance and user experience.

Practice Your Knowledge

What are the characteristics of the IndexedDB in JavaScript?

Quiz Time: Test Your Skills!

Ready to challenge what you've learned? Dive into our interactive quizzes for a deeper understanding and a fun way to reinforce your knowledge.

Do you find this helpful?