一、什么是 IndexedDB

在 HTML 里,IndexedDB 就像是一个小仓库,能让网页在浏览器里存储大量的数据。和传统的存储方式,像 cookie 或者 localStorage 比起来,IndexedDB 能存的数据更多,而且还能存储各种类型的数据,比如文件、图片啥的。它的使用场景很多,像做离线应用的时候,就可以用它把数据存到本地,这样就算没网络也能接着用;还有做数据缓存,能提高网页的响应速度。

示例(Javascript 技术栈)

// 打开一个数据库,如果数据库不存在就创建一个
const request = window.indexedDB.open('myDatabase', 1);

// 监听数据库打开成功事件
request.onsuccess = function(event) {
    const db = event.target.result;
    console.log('数据库打开成功');
};

// 监听数据库打开失败事件
request.onerror = function(event) {
    console.error('数据库打开失败:', event.target.error);
};

// 监听数据库版本变化事件,一般用于数据库升级
request.onupgradeneeded = function(event) {
    const db = event.target.result;
    // 创建一个对象存储空间,类似于数据库中的表
    const objectStore = db.createObjectStore('myObjectStore', { keyPath: 'id' });
    // 创建一个索引,方便后续查询
    objectStore.createIndex('name', 'name', { unique: false });
    console.log('数据库升级完成');
};

二、IndexedDB 的优点和缺点

优点

  1. 大容量存储:能存大量的数据,不像 cookie 有大小限制,也不像 localStorage 只能存字符串。
  2. 支持事务操作:就像银行转账一样,要么全部成功,要么全部失败,保证数据的一致性。
  3. 异步操作:不会阻塞主线程,不会让网页卡住,用户体验好。
  4. 支持各种数据类型:可以存数组、对象、二进制数据等。

缺点

  1. API 复杂:相比 localStorage 那些简单的存储方式,IndexedDB 的 API 比较复杂,学习成本高。
  2. 浏览器兼容性:不同浏览器对 IndexedDB 的支持可能不一样,有些老浏览器可能不支持。

三、IndexedDB 的使用步骤

1. 打开数据库

// 打开一个名为 myDatabase 的数据库,版本号为 1
const request = window.indexedDB.open('myDatabase', 1);

request.onsuccess = function(event) {
    const db = event.target.result;
    console.log('数据库打开成功');
};

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

request.onupgradeneeded = function(event) {
    const db = event.target.result;
    // 创建一个对象存储空间
    const objectStore = db.createObjectStore('myObjectStore', { keyPath: 'id' });
    // 创建一个索引
    objectStore.createIndex('name', 'name', { unique: false });
    console.log('数据库升级完成');
};

2. 进行事务操作

// 打开数据库
const request = window.indexedDB.open('myDatabase', 1);

request.onsuccess = function(event) {
    const db = event.target.result;
    // 开启一个读写事务
    const transaction = db.transaction(['myObjectStore'], 'readwrite');
    // 获取对象存储空间
    const objectStore = transaction.objectStore('myObjectStore');

    // 添加数据
    const data = { id: 1, name: 'John', age: 30 };
    const addRequest = objectStore.add(data);

    addRequest.onsuccess = function(event) {
        console.log('数据添加成功');
    };

    addRequest.onerror = function(event) {
        console.error('数据添加失败:', event.target.error);
    };

    // 监听事务完成事件
    transaction.oncomplete = function(event) {
        console.log('事务完成');
        db.close();
    };
};

3. 查询数据

// 打开数据库
const request = window.indexedDB.open('myDatabase', 1);

request.onsuccess = function(event) {
    const db = event.target.result;
    // 开启一个只读事务
    const transaction = db.transaction(['myObjectStore'], 'readonly');
    const objectStore = transaction.objectStore('myObjectStore');

    // 通过主键查询数据
    const getRequest = objectStore.get(1);

    getRequest.onsuccess = function(event) {
        const result = event.target.result;
        if (result) {
            console.log('查询到的数据:', result);
        } else {
            console.log('未找到数据');
        }
    };

    getRequest.onerror = function(event) {
        console.error('查询数据失败:', event.target.error);
    };

    // 监听事务完成事件
    transaction.oncomplete = function(event) {
        console.log('事务完成');
        db.close();
    };
};

4. 更新数据

// 打开数据库
const request = window.indexedDB.open('myDatabase', 1);

request.onsuccess = function(event) {
    const db = event.target.result;
    // 开启一个读写事务
    const transaction = db.transaction(['myObjectStore'], 'readwrite');
    const objectStore = transaction.objectStore('myObjectStore');

    // 通过主键获取数据
    const getRequest = objectStore.get(1);

    getRequest.onsuccess = function(event) {
        const result = event.target.result;
        if (result) {
            // 更新数据
            result.age = 31;
            const updateRequest = objectStore.put(result);

            updateRequest.onsuccess = function(event) {
                console.log('数据更新成功');
            };

            updateRequest.onerror = function(event) {
                console.error('数据更新失败:', event.target.error);
            };
        } else {
            console.log('未找到数据');
        }
    };

    getRequest.onerror = function(event) {
        console.error('查询数据失败:', event.target.error);
    };

    // 监听事务完成事件
    transaction.oncomplete = function(event) {
        console.log('事务完成');
        db.close();
    };
};

5. 删除数据

// 打开数据库
const request = window.indexedDB.open('myDatabase', 1);

request.onsuccess = function(event) {
    const db = event.target.result;
    // 开启一个读写事务
    const transaction = db.transaction(['myObjectStore'], 'readwrite');
    const objectStore = transaction.objectStore('myObjectStore');

    // 通过主键删除数据
    const deleteRequest = objectStore.delete(1);

    deleteRequest.onsuccess = function(event) {
        console.log('数据删除成功');
    };

    deleteRequest.onerror = function(event) {
        console.error('数据删除失败:', event.target.error);
    };

    // 监听事务完成事件
    transaction.oncomplete = function(event) {
        console.log('事务完成');
        db.close();
    };
};

四、应用场景

离线应用

现在很多网页都支持离线使用,比如一些新闻应用、笔记应用。在有网络的时候,把数据存到 IndexedDB 里,没网络的时候就从本地读取数据,这样用户就可以接着使用应用了。

数据缓存

对于一些经常要用到的数据,比如用户的个人信息、商品列表等,可以把这些数据存到 IndexedDB 里。下次需要用的时候,先从本地缓存里取,如果没有再去服务器请求,这样可以减少网络请求,提高网页的响应速度。

游戏数据存储

在一些 HTML5 游戏里,可以用 IndexedDB 来存储玩家的游戏进度、得分等数据,这样玩家下次打开游戏的时候就可以接着之前的进度玩。

五、注意事项

1. 错误处理

在使用 IndexedDB 的过程中,要注意错误处理。因为 IndexedDB 的操作是异步的,可能会出现各种错误,比如数据库打开失败、数据添加失败等。要给每个操作都加上错误处理,这样才能保证程序的健壮性。

2. 数据库版本管理

当数据库的结构需要改变的时候,比如要添加一个新的对象存储空间或者索引,就需要升级数据库的版本。在 onupgradeneeded 事件里进行数据库的升级操作,要注意版本号的管理,避免出现版本冲突。

3. 事务管理

在进行数据操作的时候,要合理使用事务。事务可以保证数据的一致性,如果一个事务里的操作有一个失败了,整个事务就会回滚,保证数据不会出现不一致的情况。

六、文章总结

IndexedDB 是 HTML 里一个很强大的本地存储技术,它能让网页在浏览器里存储大量的数据,支持各种数据类型,还能进行事务操作。虽然它的 API 比较复杂,浏览器兼容性也有一定问题,但是在离线应用、数据缓存、游戏数据存储等场景下,它能发挥很大的作用。在使用 IndexedDB 的时候,要注意错误处理、数据库版本管理和事务管理,这样才能高效地使用它进行数据管理。