前端数据存储方案有哪些?IndexedDB 的优势是什么?

存储方案对比

方案 容量 类型 异步 适用场景
Cookie ~4KB 字符串 ❌ 认证凭证
localStorage ~5MB 字符串 ❌ 简单 KV
sessionStorage ~5MB 字符串 ❌ 会话数据
IndexedDB ~50MB+ 结构化 ✅ 大量数据
Cache API ~50MB+ Response ✅ PWA 离线

IndexedDB

浏览器端的 NoSQL 数据库,支持事务、索引、游标。

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

request.onupgradeneeded = (e) => {
  const db = e.target.result
  // 创建对象仓库(表)
  if (!db.objectStoreNames.contains('users')) {
    const store = db.createObjectStore('users', { keyPath: 'id' })
    store.createIndex('name', 'name', { unique: false })
  }
}

request.onsuccess = (e) => {
  const db = e.target.result
  // 添加数据
  const tx = db.transaction('users', 'readwrite')
  const store = tx.objectStore('users')
  store.add({ id: 1, name: 'Tom', age: 25 })
  
  // 读取数据
  store.get(1).onsuccess = (e) => {
    console.log(e.target.result) // { id: 1, name: 'Tom', age: 25 }
  }
  
  // 遍历
  store.openCursor().onsuccess = (e) => {
    const cursor = e.target.result
    if (cursor) {
      console.log(cursor.value)
      cursor.continue()
    }
  }
}

IndexedDB 优势

  1. 大容量:通常 50MB-1GB(浏览器实现)
  2. 结构化数据:支持对象、数组、Blob
  3. 异步 API:不阻塞主线程
  4. 事务支持:保证数据一致性
  5. 索引:高效查询
  6. 同源策略:安全隔离

封装 IndexedDB(Promise 版)

function openDB(name, version, upgradeCallback) {
  return new Promise((resolve, reject) => {
    const req = indexedDB.open(name, version)
    req.onupgradeneeded = (e) => upgradeCallback(e.target.result)
    req.onsuccess = (e) => resolve(e.target.result)
    req.onerror = (e) => reject(e.target.error)
  })
}

function put(db, store, data) {
  return new Promise((resolve, reject) => {
    const tx = db.transaction(store, 'readwrite')
    tx.objectStore(store).put(data)
    tx.oncomplete = () => resolve(data)
    tx.onerror = () => reject(tx.error)
  })
}

Cache API(PWA 离线)

// 缓存资源
const cache = await caches.open('v1')
await cache.addAll([
  '/',
  '/styles.css',
  '/app.js'
])

// 从缓存读取
const cached = await caches.match('/styles.css')

// Service Worker 中拦截请求
self.addEventListener('fetch', (e) => {
  e.respondWith(
    caches.match(e.request).then(cached => 
      cached || fetch(e.request)
    )
  )
})

选择建议

同分类其他题目