You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firefox中带autoIncrement的IndexedDB存储Blob无响应问题

Firefox下IndexedDB存储Blob(autoIncrement模式)静默失败且阻塞数据库的问题

我用IndexedDB实现长媒体录制的Blob分片存储功能,代码在Chrome和Edge中运行正常,但Firefox中出现异常:数据库初始连接成功,但后续的存储请求完全无反应,没有任何报错信息,事务看起来被阻塞。

经过排查,问题明确指向使用autoIncrement+keyPath配置直接存储Blob实例的场景:

  • 手动为Blob包装对象分配自增ID可正常工作
  • 存储普通无ID对象(依赖autoIncrement)也可正常工作
  • 直接存Blob不仅会静默失败,还会导致数据库后续请求彻底失效,甚至页面重载后也无法恢复

以下是简化后的核心代码:

const dbName = 'recording'
const storeValue = 'blobs'

let connection = null
const handler = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB

function connect() {
  return new Promise((resolve, reject) => {
    const request = handler.open(dbName)

    request.onupgradeneeded = (event) => {
      const db = event.target.result

      if (db.objectStoreNames.contains(storeValue)) {
        db.deleteObjectStore(storeValue)
      }

      db.createObjectStore(storeValue, {
        keyPath: 'id',
        autoIncrement: true,
      })
    }

    request.onerror = () => reject()
    request.onsuccess = () => {
      connection = request.result
      connection.onerror = () => (connection = null)
      connection.onclose = () => (connection = null)
      resolve()
    }
  })
}

async function saveChunk(chunk) {
  if (!connection) await connect()

  return new Promise((resolve, reject) => {
    const store = connection.transaction(storeValue, 'readwrite').objectStore(storeValue)
    const req = store.add(chunk)

    req.onsuccess = () => {
      console.warn('DONE!') // Chrome/Edge触发,Firefox不触发
      resolve(req.result)
    }
    req.onerror = () => reject()
    req.transaction.oncomplete = () => console.warn('DONE!') // Chrome/Edge触发,Firefox不触发
  })
}

// 使用方式
// await saveChunk(blob)

已尝试的排查步骤:

  • 关闭其他浏览器窗口,排除连接阻塞
  • 重置Firefox配置文件
  • 多设备测试,问题一致

补充细节:

  • 代码运行在Nuxt 2.15.8开发环境(localhost:3000),作为组件Mixin使用,项目中仅此处使用IndexedDB
  • 新建数据库后短时间内事务可正常完成,但后续请求会无限排队;页面重载后初始请求也会失效

解决方案

方案1:将Blob包装为普通JS对象存储

不要直接存储Blob实例,而是将其放入一个普通对象中,保留autoIncrement和keyPath配置,Firefox可正常处理自动ID生成:

// 调用时
await saveChunk({ data: blob })

// 数据库结构无需修改,仍保持keyPath: 'id'和autoIncrement: true

方案2:手动维护自增ID

如果需要直接关联ID与Blob(不包装对象),可手动查询当前最大ID并赋值(注意:Blob本身不可添加属性,仍需包装):

async function getNextId() {
  if (!connection) await connect()
  return new Promise((resolve) => {
    const store = connection.transaction(storeValue, 'readonly').objectStore(storeValue)
    const req = store.openCursor(null, 'prev') // 查询最后一条记录
    req.onsuccess = () => {
      const cursor = req.result
      resolve(cursor ? cursor.id + 1 : 1)
    }
  })
}

// 修改saveChunk
async function saveChunk(blob) {
  const id = await getNextId()
  if (!connection) await connect()

  return new Promise((resolve, reject) => {
    const store = connection.transaction(storeValue, 'readwrite').objectStore(storeValue)
    const req = store.add({ id, data: blob }) // 包装为带ID的对象

    req.onsuccess = () => resolve(req.result)
    req.onerror = () => reject()
  })
}

原因分析

这是Firefox对IndexedDB的一个兼容性问题:当直接存储Blob类型对象且同时使用autoIncrement+keyPath配置时,Firefox无法正确完成自动ID的赋值与事务提交,导致事务静默挂起,进而阻塞后续所有数据库请求,甚至损坏数据库连接状态。而Chrome/Edge对这种场景的处理更为宽松,可正常完成自动ID生成与存储。

内容的提问来源于stack exchange,提问作者Martin Diehl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 19:50:26