你可能从未用过的浏览器 API:IndexedDB 实战入门

前端开发这几年,localStorage 和 sessionStorage 用得最多,cookie 偶尔也要打打交道。但说到 IndexedDB,很多人的反应是:"听说过,但没用过。"

今天聊聊这个被低估的浏览器内置数据库。

一、为什么需要另一个存储方案?

先看个实际场景。朋友公司做电商后台,产品经理要求:"能不能在列表页缓存 5000 条商品数据,让筛选和搜索快一点?"

第一版用 localStorage:

javascript 复制代码
// 存储
localStorage.setItem('products', JSON.stringify(products)) // 5000条数据,页面卡了2秒

// 搜索
const keyword = '手机'
const allProducts = JSON.parse(localStorage.getItem('products')) // 又卡1秒
const results = allProducts.filter(p => p.name.includes(keyword)) // 遍历5000次

上线后用户反馈:"筛选时浏览器像卡住了一样。"

问题在哪?localStorage 有硬伤:

  • 同步操作,数据量大就阻塞页面
  • 只能存字符串,对象要序列化
  • 容量小(通常 5-10MB)
  • 只能全量读取,无法高效查询

二、IndexedDB 是什么?

简单说,它是浏览器里的 NoSQL 数据库。2011 年就出现了,但很多人不知道或觉得"用不上"。

几个关键特点:

  1. 容量大:通常能占硬盘 50%,几个 GB 没问题
  2. 异步操作:不卡页面
  3. 支持索引:查询速度快
  4. 能存多种类型:对象、文件、二进制数据都行

三、一个简单示例

如果你没用过,先看看基本用法:

javascript 复制代码
// 1. 打开数据库
const request = indexedDB.open('myDB', 1)

// 2. 创建表结构(第一次或升级时)
request.onupgradeneeded = function(event) {
  const db = event.target.result
  
  // 创建对象存储(类似表)
  const store = db.createObjectStore('products', {
    keyPath: 'id',      // 主键
    autoIncrement: true // 自动生成ID
  })
  
  // 创建索引(加速查询的关键)
  store.createIndex('name', 'name')      // 按名称查
  store.createIndex('price', 'price')    // 按价格查
  store.createIndex('category', 'category') // 按分类查
}

// 3. 数据库就绪
request.onsuccess = function(event) {
  const db = event.target.result
  console.log('数据库已就绪')
}

四、核心优势:查询性能

这是 IndexedDB 真正厉害的地方。同样的 5000 条商品数据,查询完全不同:

javascript 复制代码
// 用索引查,不需要遍历所有数据
async function searchProducts(keyword) {
  const transaction = db.transaction(['products'], 'readonly')
  const store = transaction.objectStore('products')
  const index = store.index('name') // 使用索引
  
  // 只搜索相关范围
  const range = IDBKeyRange.bound(keyword, keyword + '\uffff')
  const request = index.openCursor(range)
  
  return new Promise((resolve) => {
    const results = []
    request.onsuccess = function(event) {
      const cursor = event.target.result
      if (cursor) {
        results.push(cursor.value)
        cursor.continue() // 继续下一个
      } else {
        resolve(results) // 搜索完成
      }
    }
  })
}

// 毫秒级响应,不卡页面
const results = await searchProducts('手机')

你可以创建多个索引,实现各种复杂查询:

  • 价格区间筛选
  • 多条件组合查询
  • 分类统计
  • 模糊搜索

五、适用场景

什么情况下该考虑 IndexedDB?

1. 离线应用

邮件客户端、文档编辑器、笔记应用。数据先存本地,有网再同步。

2. 大数据缓存

电商商品目录、大量配置项、历史数据。替代接口频繁请求。

3. 文件管理

图片、PDF、音视频的本地缓存。不用每次都下载。

4. 游戏数据

存档、配置、资源文件。支持离线游戏。

5. 分析数据

收集用户行为,批量上传。避免频繁网络请求。

六、实用建议

1. 用封装库简化开发

原生 API 确实有点繁琐。推荐这些库:

javascript 复制代码
// 用 idb 库(推荐)
import { openDB } from 'idb'

const db = await openDB('my-db', 1, {
  upgrade(db) {
    db.createObjectStore('products')
  }
})

// 操作简单多了
await db.add('products', { name: '商品1', price: 100 })
const products = await db.getAll('products')

2. 渐进增强

先判断支持性,不支持就降级:

javascript 复制代码
function getStorage() {
  if ('indexedDB' in window) {
    return {
      type: 'indexedDB',
      save: saveToIndexedDB,
      load: loadFromIndexedDB
    }
  } else {
    console.log('降级到 localStorage')
    return {
      type: 'localStorage',
      save: saveToLocalStorage,
      load: loadFromLocalStorage
    }
  }
}

3. 注意版本迁移

修改表结构需要升级版本:

javascript 复制代码
const request = indexedDB.open('myDB', 2) // 版本号+1

request.onupgradeneeded = function(event) {
  const db = event.target.result
  const oldVersion = event.oldVersion
  
  if (oldVersion < 1) {
    // 初始版本逻辑
  }
  
  if (oldVersion < 2) {
    // 版本2的升级逻辑
    // 比如添加新索引
    const store = event.currentTarget.transaction.objectStore('products')
    store.createIndex('createdAt', 'createdAt')
  }
}

七、什么时候不用?

IndexedDB 虽好,但也不是万能:

  • 存个用户 token → 用 localStorage 或 cookie
  • 会话级临时数据 → 用 sessionStorage
  • 简单配置项 → localStorage 更方便
  • 需要服务端读取 → cookie

记住:技术选型要看具体需求,不是越高级越好。

八、开始尝试

如果你从没用过 IndexedDB,可以从这些开始:

  1. 缓存接口数据:把频繁请求的 API 结果缓存起来
  2. 离线收藏功能:用户收藏的内容存本地
  3. 图片懒加载缓存:看过的图片存起来
  4. 表单草稿:复杂的表单数据实时保存

不需要一开始就大动干戈。找个合适的场景,先试试水。

写在最后

IndexedDB 在前端领域存在感不强,可能因为它解决的问题不是每个项目都会遇到。但当你真的需要处理大量客户端数据时,它会是个很好的选择。

技术没有绝对的好坏,只有合适与否。知道它的存在,了解它的能力,当合适的需求出现时,你就能做出更好的选择。


看完有点兴趣了?可以在个人项目里试试 IndexedDB,遇到问题欢迎交流。如果你已经在用,有什么经验或踩坑故事?评论区聊聊。

相关推荐
mCell6 小时前
如何零成本搭建个人站点
前端·程序员·github
mCell7 小时前
为什么 Memo Code 先做 CLI:以及终端输入框到底有多难搞
前端·设计模式·agent
恋猫de小郭7 小时前
AI 在提高你工作效率的同时,也一直在增加你的疲惫和焦虑
前端·人工智能·ai编程
少云清7 小时前
【安全测试】2_客户端脚本安全测试 _XSS和CSRF
前端·xss·csrf
银烛木8 小时前
黑马程序员前端h5+css3
前端·css·css3
m0_607076608 小时前
CSS3 转换,快手前端面试经验,隔壁都馋哭了
前端·面试·css3
听海边涛声8 小时前
CSS3 图片模糊处理
前端·css·css3
IT、木易8 小时前
css3 backdrop-filter 在移动端 Safari 上导致渲染性能急剧下降的优化方案有哪些?
前端·css3·safari
0思必得08 小时前
[Web自动化] Selenium无头模式
前端·爬虫·selenium·自动化·web自动化
anOnion8 小时前
构建无障碍组件之Dialog Pattern
前端·html·交互设计