阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > IndexedDB的基本概念与使用

IndexedDB的基本概念与使用

作者:陈川 阅读数:36069人阅读 分类: HTML

IndexedDB是HTML5提供的一种浏览器端数据库,适合存储大量结构化数据。它基于键值对存储,支持事务处理,能够在离线状态下工作,适合复杂Web应用的数据管理需求。

IndexedDB的核心概念

IndexedDB的核心概念包括数据库、对象仓库、索引和事务。数据库是最高层次的容器,每个数据库包含多个对象仓库。对象仓库类似于关系型数据库中的表,用于存储实际数据。索引用于快速查询数据,事务则保证数据操作的原子性。

数据库采用版本控制机制,每次结构变更都需要升级版本号。例如创建新对象仓库或修改现有结构时,必须通过版本升级来实现:

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

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

数据库的打开与关闭

打开数据库使用indexedDB.open()方法,该方法返回一个IDBRequest对象。第一个参数是数据库名称,第二个可选参数是版本号。如果数据库不存在,会自动创建。

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

openRequest.onerror = (event) => {
  console.error('数据库打开失败:', event.target.error);
};

openRequest.onsuccess = (event) => {
  const db = event.target.result;
  console.log('数据库打开成功');
  // 使用完毕后关闭连接
  db.close();
};

注意关闭数据库连接很重要,特别是在SPA应用中,避免内存泄漏。

对象仓库操作

对象仓库是IndexedDB存储数据的基本单位。创建对象仓库只能在onupgradeneeded事件中完成。创建时可以指定主键和自动增量选项:

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  
  // 创建主键为id的对象仓库
  const store = db.createObjectStore('books', {
    keyPath: 'id',
    autoIncrement: true
  });
  
  // 创建索引
  store.createIndex('by_title', 'title', { unique: false });
  store.createIndex('by_author', 'author', { unique: false });
};

数据增删改查

IndexedDB的所有数据操作都必须在事务中进行。事务分为只读和读写两种模式。

添加数据示例:

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

const book = {
  title: 'JavaScript高级程序设计',
  author: 'Nicholas C. Zakas',
  year: 2020
};

const request = store.add(book);

request.onsuccess = () => {
  console.log('数据添加成功');
};

查询数据可以通过主键或索引:

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

const request = index.get('JavaScript高级程序设计');

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

事务处理

IndexedDB的事务是自动提交的,不需要手动调用提交方法。但需要注意事务的生命周期:

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

// 事务自动超时时间为60秒
transaction.oncomplete = () => {
  console.log('事务完成');
};

transaction.onerror = (event) => {
  console.error('事务出错:', event.target.error);
};

// 所有操作必须在事务活跃期间完成
setTimeout(() => {
  // 这会导致错误,因为事务可能已经结束
  store.add({ title: '超时添加的书' });
}, 1000);

游标遍历

对于大量数据的遍历,需要使用游标:

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('遍历结束');
  }
};

可以结合索引和游标实现范围查询:

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();
  }
};

性能优化

IndexedDB使用时需要注意几个性能要点:

  1. 批量操作使用事务合并
  2. 合理使用索引加速查询
  3. 避免在事务中执行耗时操作
  4. 大型数据分块处理

批量写入示例:

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);
    });
  });
}

错误处理

IndexedDB操作可能产生的错误需要妥善处理:

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

request.onerror = (event) => {
  const error = event.target.error;
  if (error.name === 'VersionError') {
    console.error('版本号低于当前版本');
  } else if (error.name === 'QuotaExceededError') {
    console.error('存储空间不足');
  } else {
    console.error('数据库错误:', error);
  }
};

实际应用场景

IndexedDB适合以下场景:

  • 离线Web应用数据存储
  • 客户端大数据缓存
  • 需要复杂查询的本地数据
  • 需要事务支持的数据操作

例如实现一个离线笔记应用:

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);
    });
  }
}

浏览器兼容性

现代浏览器基本都支持IndexedDB,但需要注意:

  • IE10+支持但前缀不同(msIndexedDB)
  • 移动端浏览器支持良好
  • 隐私模式下可能有限制

检测浏览器支持情况:

if (!window.indexedDB) {
  console.warn('当前浏览器不支持IndexedDB');
  // 可以考虑降级方案如localStorage
}

调试工具

浏览器开发者工具提供IndexedDB调试功能:

  • Chrome DevTools的Application面板
  • Firefox的Storage Inspector
  • Edge的IndexedDB查看器

这些工具可以查看数据库结构、存储内容和执行简单查询。

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

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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌