HTML5怎样用IndexedDB存取值获取数据_HTML5IndexedDB用法【通识】

9次阅读

IndexedDB打开失败通常因未处理onupgradeneeded事件,它非错误而是必经阶段,须在此创建objectStore;onError才表示真实异常,如权限拒绝或磁盘满;DataCloneError源于存入不可克隆数据;get()返回undefined可能因key类型不匹配或事务已关闭;批量写入应复用同一事务并用put()替代多次add()。

HTML5怎样用IndexedDB存取值获取数据_HTML5IndexedDB用法【通识】

IndexedDB 打开数据库失败:onerror 和 onupgradeneeded 怎么区分?

绝大多数初学者卡在第一步——indexedDB.open() 调用后既没进 onsuccess 也没报错,实际是触发了 onupgradeneeded。这个事件**不是错误**,而是数据库首次创建或版本升级的必经阶段,必须在此回调里定义 objectStore,否则后续所有读写都会失败(报 InvalidStateError: Failed to execute 'transaction' on 'IDBdatabase': The database connection is closing 或类似错误)。

关键点:

  • onupgradeneeded 中必须调用 db.createObjectStore('storeName', { keyPath: 'id' }),否则后续事务会因 store 不存在而拒绝执行
  • 如果只是想读已有数据,但忘记处理 onupgradeneededdb 对象虽存在,却无法开启事务(db.transaction(...) 报错)
  • onerror 真正触发时,通常意味着权限被拒(如私密模式下 safari 默认禁用 IndexedDB)、磁盘满、或数据库损坏,此时 Event.target.error 会给出具体原因

存对象时提示 “DataCloneError:Failed to execute ‘add’ on ‘IDBObjectStore’”

这是最常被忽略的兼容性陷阱:IndexedDB **只接受可结构化克隆(structured clone)的数据**,不支持函数、undefined、symboldom 节点、循环引用对象,甚至 date 实例在部分旧版浏览器中也会失败。

安全写法:

立即学习前端免费学习笔记(深入)”;

  • 存前用 jsON.parse(json.stringify(obj)) 做浅净化(注意:会丢掉 Date、regexp、undefined 等)
  • 更稳妥的做法是手动序列化:把 new Date() 转成 date.toISOString() 字符串,把 map/Set 转为数组
  • 避免直接存 thiseventdocument.querySelector(...) 这类原生对象
const transaction = db.transaction(['users'], 'readwrite'); const store = transaction.objectStore('users'); // ✅ 安全 store.add({ id: 1, name: 'Alice', createdAt: new Date().toISOString() });  // ❌ 报 DataCloneError store.add({ id: 1, name: 'Alice', now: new Date() }); // Date 对象在某些环境不被允许

get() 返回 undefined 却没报错:key 匹配逻辑和事务模式要注意什么?

IDBObjectStore.get(key) 查不到时**静默返回 undefined**,不会抛异常,容易误判为“成功但值为空”。根本原因常出在两个地方:key 类型不一致、或事务已关闭。

典型坑:

  • 存的时候用字符串 '123' 作 key,查时传数字 123 —— IndexedDB 的 key 比较严格,'123' !== 123
  • 异步操作中,transaction.oncomplete 触发后,事务自动关闭,此时再调用 get() 会立即失败(但不报错,返回 undefined)
  • 没指定 keyPath 且没传 autoIncrement: true,又没手动传 key,add() 会失败,导致后续 get() 查不到
// ✅ 正确:确保 key 类型一致,且在事务活跃期内调用 const transaction = db.transaction(['logs'], 'readonly'); const store = transaction.objectStore('logs'); const request = store.get('log_20240520'); // 字符串 key  request.onsuccess = () => {   if (request.result === undefined) {     console.log('没找到该 log');   } else {     console.log('查到:', request.result);   } };

批量写入慢、频繁阻塞 ui?用 add() 还是 put()?要不要用游标?

单条 add() / put() 没问题,但循环 1000 次逐个写,性能极差。根本原因是每次请求都新建一个事务,触发多次磁盘 I/O 和事件调度。

提速关键:

  • **所有写操作必须塞进同一个 readwrite 事务**,哪怕跨多个 objectStore
  • put()add() 更通用:它会覆盖同 key 记录,而 add() 遇到重复 key 直接报 ConstraintError
  • 批量导入场景,优先用 store.put(item, key),配合 transaction.oncomplete 统一收尾,别等每个 request.success
  • 遍历大量数据用 openCursor(),不用反复 get() —— 游标一次打开,顺序读取,内存占用

复杂点在于:事务生命周期必须手动管理,不能依赖闭包或异步等待。一旦离开当前函数作用域,又没显式 hold 住 transaction,它就可能提前关闭。

text=ZqhQzanResources