indexeddb构建离线web应用的关键在于数据组织、索引设计、事务控制与同步策略:需合理建模对象仓库与多级索引,封装promise化操作,坚持本地优先原则,并协同service worker实现资源与api的离线兜底。

用 IndexedDB 构建高性能本地离线 Web 应用,关键不在“能不能存”,而在“怎么组织、怎么查、怎么同步”。它不是 localStorage 的放大版,而是一套需要设计的数据层——结构清晰、索引合理、事务可控、升级平滑。
设计合理的对象仓库与索引
一个对象仓库(Object Store)对应一类业务数据,比如 todos、users 或 cacheEntries。主键(keyPath)要选稳定且唯一字段,如 id;若无天然主键,可启用 autoIncrement: true 让 IndexedDB 自动分配数字 ID。
索引决定查询效率。别只建一个主键索引——按业务高频查询路径补上二级索引:
- 待办事项按状态筛选?建
completed索引 - 用户列表按邮箱搜索?建
email唯一索引 - 日志需按时间范围拉取?建
timestamp非唯一索引 - 商品缓存需按类型+过期时间联合过滤?可建多级索引或组合字段(如
type_expiredAt)
封装异步操作,避免回调地狱
原生 IndexedDB 是基于事件的 API,直接使用容易写出嵌套回调。推荐封装成 Promise 风格,统一错误处理和事务生命周期:
- 每个读写操作都明确指定事务类型:
"readonly"用于查询,"readwrite"用于增删改 - 事务对象(
IDBTransaction)监听oncomplete和onerror,不要依赖单个请求的 success/error - 批量写入优先用
store.put()多次调用,而非循环开多个事务——一次readwrite事务内完成所有操作更高效
离线优先:本地为源,网络为通道
真正的离线优先不是“断网时能读”,而是“所有操作默认走本地,网络仅用于后台同步”:
- 新增一条笔记,先存入 IndexedDB,并标记
synced: false - 页面加载时,直接从本地读取最新数据,不等网络响应
- 监听
navigator.onLine或使用fetch失败兜底,触发同步队列 - 同步成功后更新本地记录的
synced和服务端serverId,失败则保留并重试(可加指数退避)
配合 Service Worker 实现无缝离线体验
IndexedDB 负责结构化业务数据,Service Worker 负责静态资源与 API 请求拦截:
- 用
cachesAPI 缓存 HTML/CSS/JS 图片等资源,保证页面骨架可离线加载 - 在 Service Worker 的
fetch事件中,对 API 请求做 fallback:先查 IndexedDB,再发网络请求;返回后更新本地库 - 结合
Background Sync(如支持)实现“联网即同步”,无需用户主动刷新











