你可能从未用过的浏览器存储神器:IndexedDB 简明指南
前端开发这几年,localStorage 和 sessionStorage 用得最多,cookie 偶尔也要打打交道。但说到 IndexedDB,很多人的反应是:“听说过,但没用过。” 今天聊聊这个被低估的浏览器内置数据库。 先看个实际场景。朋友公司做电商后台,产品经理要求:“能不能在列表页缓存 5000 条商品数据,让筛选和搜索快一点?” 第一版用 localStorage: 上线后用户反馈:“筛选时浏览器像卡住了一样。” 问题在哪?localStorage 有硬伤: 简单说,它是浏览器里的 NoSQL 数据库。2011 年就出现了,但很多人不知道或觉得“用不上”。 几个关键特点: 如果你没用过,先看看基本用法: 这是 IndexedDB 真正厉害的地方。同样的 5000 条商品数据,查询完全不同: 你可以创建多个索引,实现各种复杂查询: 什么情况下该考虑 IndexedDB? 邮件客户端、文档编辑器、笔记应用。数据先存本地,有网再同步。 电商商品目录、大量配置项、历史数据。替代接口频繁请求。 图片、PDF、音视频的本地缓存。不用每次都下载。 存档、配置、资源文件。支持离线游戏。 收集用户行为,批量上传。避免频繁网络请求。 原生 API 确实有点繁琐。推荐这些库: 先判断支持性,不支持就降级: 修改表结构需要升级版本: IndexedDB 虽好,但也不是万能: 记住:技术选型要看具体需求,不是越高级越好。 如果你从没用过 IndexedDB,可以从这些开始: 不需要一开始就大动干戈。找个合适的场景,先试试水。 IndexedDB 在前端领域存在感不强,可能因为它解决的问题不是每个项目都会遇到。但当你真的需要处理大量客户端数据时,它会是个很好的选择。 技术没有绝对的好坏,只有合适与否。知道它的存在,了解它的能力,当合适的需求出现时,你就能做出更好的选择。 看完有点兴趣了?可以在个人项目里试试 IndexedDB,遇到问题欢迎交流。如果你已经在用,有什么经验或踩坑故事?评论区聊聊。 本文由mdnice多平台发布一、为什么需要另一个存储方案?
// 存储
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次二、IndexedDB 是什么?
三、一个简单示例
// 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('数据库已就绪')
}四、核心优势:查询性能
// 用索引查,不需要遍历所有数据
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('手机')五、适用场景
1. 离线应用
2. 大数据缓存
3. 文件管理
4. 游戏数据
5. 分析数据
六、实用建议
1. 用封装库简化开发
// 用 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. 渐进增强
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. 注意版本迁移
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')
}
}七、什么时候不用?
八、开始尝试
写在最后
