阿里云主机折上折
  • 微信号
Current Site:Index > Basic concepts and usage of IndexedDB

Basic concepts and usage of IndexedDB

Author:Chuan Chen 阅读数:36068人阅读 分类: HTML

IndexedDB is a browser-side database provided by HTML5, suitable for storing large amounts of structured data. It is based on key-value storage, supports transaction processing, can work offline, and is ideal for managing data in complex web applications.

Core Concepts of IndexedDB

The core concepts of IndexedDB include databases, object stores, indexes, and transactions. A database is the highest-level container, with each database containing multiple object stores. Object stores are similar to tables in relational databases and are used to store actual data. Indexes enable fast data queries, while transactions ensure the atomicity of data operations.

Databases use a version control mechanism, where every structural change requires a version number upgrade. For example, when creating a new object store or modifying an existing structure, the change must be implemented through a version upgrade:

const request = indexedDB.open('myDatabase', 2);

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  if (!db.objectStoreNames.contains('users')) {
    db.createObjectStore('users', { keyPath: 'id' });
  }
};

Opening and Closing Databases

To open a database, use the indexedDB.open() method, which returns an IDBRequest object. The first parameter is the database name, and the second optional parameter is the version number. If the database does not exist, it will be created automatically.

const openRequest = indexedDB.open('myDatabase', 1);

openRequest.onerror = (event) => {
  console.error('Failed to open database:', event.target.error);
};

openRequest.onsuccess = (event) => {
  const db = event.target.result;
  console.log('Database opened successfully');
  // Close the connection after use
  db.close();
};

Note that closing the database connection is important, especially in single-page applications (SPAs), to avoid memory leaks.

Object Store Operations

Object stores are the basic units of data storage in IndexedDB. Creating an object store can only be done within the onupgradeneeded event. During creation, you can specify primary keys and auto-increment options:

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  
  // Create an object store with 'id' as the primary key
  const store = db.createObjectStore('books', {
    keyPath: 'id',
    autoIncrement: true
  });
  
  // Create indexes
  store.createIndex('by_title', 'title', { unique: false });
  store.createIndex('by_author', 'author', { unique: false });
};

CRUD Operations

All data operations in IndexedDB must be performed within transactions. Transactions come in two modes: read-only and read-write.

Example of adding data:

const transaction = db.transaction(['books'], 'readwrite');
const store = transaction.objectStore('books');

const book = {
  title: 'JavaScript: The Definitive Guide',
  author: 'Nicholas C. Zakas',
  year: 2020
};

const request = store.add(book);

request.onsuccess = () => {
  console.log('Data added successfully');
};

Data can be queried using primary keys or indexes:

const transaction = db.transaction(['books'], 'readonly');
const store = transaction.objectStore('books');
const index = store.index('by_title');

const request = index.get('JavaScript: The Definitive Guide');

request.onsuccess = (event) => {
  const book = event.target.result;
  console.log(book);
};

Transaction Handling

IndexedDB transactions are auto-committed and do not require manual commit calls. However, it is important to note the transaction lifecycle:

const transaction = db.transaction(['books'], 'readwrite');
const store = transaction.objectStore('books');

// The transaction automatically times out after 60 seconds
transaction.oncomplete = () => {
  console.log('Transaction completed');
};

transaction.onerror = (event) => {
  console.error('Transaction error:', event.target.error);
};

// All operations must be completed while the transaction is active
setTimeout(() => {
  // This will cause an error because the transaction may have already ended
  store.add({ title: 'Book added after timeout' });
}, 1000);

Cursor Iteration

For traversing large datasets, cursors are used:

const transaction = db.transaction(['books'], 'readonly');
const store = transaction.objectStore('books');
const request = store.openCursor();

request.onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    console.log(cursor.key, cursor.value);
    cursor.continue();
  } else {
    console.log('Iteration complete');
  }
};

Cursors can be combined with indexes for range queries:

const range = IDBKeyRange.bound('A', 'M');
const index = store.index('by_title');
const request = index.openCursor(range);

request.onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) {
    console.log(cursor.value.title);
    cursor.continue();
  }
};

Performance Optimization

When using IndexedDB, consider the following performance tips:

  1. Batch operations using transaction merging
  2. Use indexes wisely to speed up queries
  3. Avoid time-consuming operations within transactions
  4. Process large data in chunks

Example of batch writing:

function addMultipleBooks(db, books) {
  return new Promise((resolve, reject) => {
    const transaction = db.transaction(['books'], 'readwrite');
    const store = transaction.objectStore('books');
    
    transaction.oncomplete = () => resolve();
    transaction.onerror = (event) => reject(event.target.error);
    
    books.forEach(book => {
      store.add(book);
    });
  });
}

Error Handling

Errors in IndexedDB operations should be handled properly:

const request = indexedDB.open('myDatabase');

request.onerror = (event) => {
  const error = event.target.error;
  if (error.name === 'VersionError') {
    console.error('Version number is lower than the current version');
  } else if (error.name === 'QuotaExceededError') {
    console.error('Insufficient storage space');
  } else {
    console.error('Database error:', error);
  }
};

Practical Use Cases

IndexedDB is suitable for the following scenarios:

  • Offline web application data storage
  • Client-side caching of large datasets
  • Local data requiring complex queries
  • Data operations requiring transaction support

For example, implementing an offline notes application:

class NotesDB {
  constructor() {
    this.dbPromise = new Promise((resolve, reject) => {
      const request = indexedDB.open('NotesDB', 1);
      
      request.onupgradeneeded = (event) => {
        const db = event.target.result;
        if (!db.objectStoreNames.contains('notes')) {
          const store = db.createObjectStore('notes', {
            keyPath: 'id',
            autoIncrement: true
          });
          store.createIndex('by_date', 'createdAt', { unique: false });
        }
      };
      
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }

  async addNote(note) {
    const db = await this.dbPromise;
    return new Promise((resolve, reject) => {
      const transaction = db.transaction(['notes'], 'readwrite');
      const store = transaction.objectStore('notes');
      
      const request = store.add({
        ...note,
        createdAt: new Date()
      });
      
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }

  async getNotes() {
    const db = await this.dbPromise;
    return new Promise((resolve, reject) => {
      const transaction = db.transaction(['notes'], 'readonly');
      const store = transaction.objectStore('notes');
      const index = store.index('by_date');
      
      const request = index.getAll();
      
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }
}

Browser Compatibility

Most modern browsers support IndexedDB, but note the following:

  • IE10+ supports it but with a different prefix (msIndexedDB)
  • Mobile browsers generally have good support
  • Private browsing modes may impose limitations

Check browser support:

if (!window.indexedDB) {
  console.warn('Current browser does not support IndexedDB');
  // Consider fallback options like localStorage
}

Debugging Tools

Browser developer tools provide IndexedDB debugging features:

  • Chrome DevTools' Application panel
  • Firefox's Storage Inspector
  • Edge's IndexedDB viewer

These tools allow you to inspect database structures, stored content, and perform simple queries.

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.