前端数据存储新选择:IndexedDB与Dexie.js技术指南

前端数据存储新选择:IndexedDB与Dexie.js技术指南

一、IndexedDB:浏览器端的NoSQL数据库

IndexedDB(Indexed Database API)是浏览器内置的事务型NoSQL数据库系统,专为客户端存储大量结构化数据而设计。与传统的localStorage相比,IndexedDB提供了更强大的功能和更好的性能表现。

核心特性

大容量存储:IndexedDB几乎没有存储上限,通常可存储50MB到数百MB的数据,远超localStorage的5MB限制。这使其成为存储大型应用状态、离线数据和媒体资源的理想选择。

异步操作:所有操作都是异步的,不会阻塞主线程,确保页面流畅性。在处理超过500KB数据时,IndexedDB的性能优势尤为明显,页面响应性能可提升40%以上。

事务支持:提供原子性操作机制,确保数据操作的完整性和一致性。在复杂操作(如转账类操作)时非常关键。

结构化数据存储:支持存储JavaScript对象、Blob、ArrayBuffer等二进制数据,无需手动序列化。同时支持索引和复杂查询,可实现按字段筛选、排序、范围查询等高级操作。

适用场景

  • 离线优先应用(PWA):在用户离线时完整保存应用数据,网络恢复后同步到服务器
  • 富文本编辑器/复杂表单:频繁静默保存用户输入内容,即使浏览器崩溃也能恢复
  • 大型应用数据缓存:首次加载后存入本地,后续访问优先从本地读取
  • 客户端日志/分析数据持久化:批量存储用户行为日志,待网络良好时统一上报

二、Dexie.js:简化IndexedDB操作的利器

Dexie.js是一个轻量级的JavaScript库,专门用于简化IndexedDB的操作。它通过封装IndexedDB的复杂API,提供了更直观、易用的接口,使开发者能够更高效地进行前端持久化数据存储。

核心优势

极简API设计:Dexie.js提供了简洁的链式调用API,大幅降低了代码量。原生IndexedDB需要10+行代码的事务操作,Dexie.js一行即可搞定。

Promise和Async/Await支持:所有接口都返回Promise,支持现代异步编程方式,避免回调地狱。

强大的查询能力:支持范围查询、多条件查询、复合索引、排序和分页等复杂操作,查询语法类似MongoDB。

事务管理:内置事务机制,确保多个数据库操作的原子性。

跨浏览器兼容性:兼容Chrome、Firefox、Safari、Edge等主流现代浏览器。

安装方式

# npm安装npminstall dexie 

三、Vue3中使用Dexie.js

基础配置

首先在项目中创建数据库配置文件:

// src/utils/db.jsimport Dexie from'dexie'const db =newDexie('MyVueAppDB')// 定义数据库表和索引 db.version(1).stores({users:'++id, name, age, email',posts:'++id, title, content, userId, createdAt'})exportdefault db 

组合式API封装

// src/composables/useUsers.jsimport{ ref }from'vue'import db from'@/utils/db'exportfunctionuseUsers(){const users =ref([])const loading =ref(false)const error =ref(null)// 获取所有用户constfetchUsers=async()=>{ loading.value =truetry{ users.value =await db.users.toArray()}catch(err){ error.value = err.message }finally{ loading.value =false}}// 添加用户constaddUser=async(userData)=>{try{const id =await db.users.add(userData)awaitfetchUsers()// 重新获取数据return id }catch(err){ error.value = err.message throw err }}// 更新用户constupdateUser=async(id, updates)=>{try{await db.users.update(id, updates)awaitfetchUsers()}catch(err){ error.value = err.message throw err }}// 删除用户constdeleteUser=async(id)=>{try{await db.users.delete(id)awaitfetchUsers()}catch(err){ error.value = err.message throw err }}// 复杂查询:按年龄范围查询constgetUsersByAgeRange=async(minAge, maxAge)=>{try{returnawait db.users .where('age').between(minAge, maxAge).toArray()}catch(err){ error.value = err.message throw err }}return{ users, loading, error, fetchUsers, addUser, updateUser, deleteUser, getUsersByAgeRange }}

在组件中使用

<template><div><h2>用户列表</h2><div v-if="loading">加载中...</div><div v-else-if="error"class="error">{{ error }}</div><div v-else><ul><li v-for="user in users":key="user.id">{{ user.name }}-{{ user.age }}岁 <button @click="deleteUser(user.id)">删除</button></li></ul></div><form @submit.prevent="addNewUser"><input v-model="newUser.name" placeholder="姓名" required><input v-model.number="newUser.age" type="number" placeholder="年龄" required><input v-model="newUser.email" type="email" placeholder="邮箱"><button type="submit">添加用户</button></form></div></template><script setup>import{ ref, onMounted }from'vue'import{ useUsers }from'@/composables/useUsers'const{ users, loading, error, fetchUsers, addUser, deleteUser }=useUsers()const newUser =ref({name:'',age:'',email:''})onMounted(()=>{fetchUsers()})constaddNewUser=async()=>{try{awaitaddUser(newUser.value) newUser.value ={name:'',age:'',email:''}}catch(err){ console.error('添加用户失败:', err)}}</script>

实时查询(Live Query)

Dexie.js提供了实时查询功能,当数据库数据变化时自动更新UI:

// 使用实时查询import{ liveQuery }from"dexie";// 在Vue3中需要额外处理import{ from }from'@vueuse/rxjs'import{ useObservable }from'@vueuse/rxjs'const users =useObservable(from(liveQuery(async()=>{returnawait db.users.toArray()})))

四、React中使用Dexie.js

安装依赖

npminstall dexie dexie-react-hooks 

数据库配置

// src/db.jsimport Dexie from'dexie'classAppDatabaseextendsDexie{constructor(){super('MyReactAppDB')this.version(1).stores({todos:'++id, title, completed, createdAt',users:'++id, name, email, age'})this.todos =this.table('todos')this.users =this.table('users')}}exportconst db =newAppDatabase()

自定义Hook封装

// src/hooks/useTodos.jsimport{ useState, useEffect }from'react'import{ useLiveQuery }from'dexie-react-hooks'import{ db }from'../db'exportfunctionuseTodos(){const[loading, setLoading]=useState(false)const[error, setError]=useState(null)// 使用useLiveQuery实现实时查询const todos =useLiveQuery(()=> db.todos.toArray(),[],[])constaddTodo=async(title)=>{setLoading(true)try{await db.todos.add({ title,completed:false,createdAt:newDate()})}catch(err){setError(err.message)}finally{setLoading(false)}}consttoggleTodo=async(id, completed)=>{try{await db.todos.update(id,{ completed })}catch(err){setError(err.message)}}constdeleteTodo=async(id)=>{try{await db.todos.delete(id)}catch(err){setError(err.message)}}constclearCompleted=async()=>{try{await db.todos.where('completed').equals(true).delete()}catch(err){setError(err.message)}}return{todos: todos ||[], loading, error, addTodo, toggleTodo, deleteTodo, clearCompleted }}

组件中使用

// src/components/TodoList.jsximport React,{ useState }from'react'import{ useTodos }from'../hooks/useTodos'functionTodoList(){const{ todos, loading, error, addTodo, toggleTodo, deleteTodo, clearCompleted }=useTodos()const[newTodoTitle, setNewTodoTitle]=useState('')consthandleSubmit=(e)=>{ e.preventDefault()if(newTodoTitle.trim()){addTodo(newTodoTitle.trim())setNewTodoTitle('')}}if(loading)return<div>加载中...</div>if(error)return<div>错误:{error}</div>return(<div><h2>待办事项</h2><form onSubmit={handleSubmit}><input type="text" value={newTodoTitle} onChange={(e)=>setNewTodoTitle(e.target.value)} placeholder="添加新待办事项"/><button type="submit">添加</button></form><ul>{todos.map(todo=>(<li key={todo.id}><input type="checkbox" checked={todo.completed} onChange={()=>toggleTodo(todo.id,!todo.completed)}/><span style={{textDecoration: todo.completed ?'line-through':'none'}}>{todo.title}</span><button onClick={()=>deleteTodo(todo.id)}>删除</button></li>))}</ul><button onClick={clearCompleted}>清除已完成</button></div>)}exportdefault TodoList 

复杂查询示例

// 范围查询:查询年龄在20-30岁之间的用户const youngUsers =await db.users .where('age').between(20,30).toArray()// 多条件查询:查询特定类别且价格小于200的商品const results =await db.items .where('category').equals('A').and(item=> item.price <200).toArray()// 排序和分页const paginatedResults =await db.items .orderBy('price').offset(10)// 跳过前10条.limit(5)// 获取5条.toArray()

五、最佳实践与性能优化

1. 合理设计索引

为高频查询字段创建索引,避免全表扫描:

db.version(1).stores({products:'++id, name, price, category, [category+price]'})

2. 批量操作优化

使用批量操作API提高性能:

// 批量添加await db.users.bulkAdd([{name:'Alice',age:25},{name:'Bob',age:30},{name:'Charlie',age:28}])// 批量更新await db.users.bulkPut([{id:1,name:'Alice Smith',age:26},{id:2,name:'Bob Johnson',age:31}])

3. 事务优化

将相关操作放在同一事务中执行:

await db.transaction('rw', db.users, db.posts,async()=>{const userId =await db.users.add({name:'John',age:25})await db.posts.add({title:'Hello World',content:'...', userId })})

4. 错误处理

try{await db.users.add({name:'Alice',age:25})}catch(error){if(error.name ==='ConstraintError'){ console.error('数据约束错误:', error.message)}else{ console.error('未知错误:', error)}}

5. 数据库版本升级

db.version(2).stores({users:'++id, name, age, email, city'// 新增city字段}) db.version(3).upgrade(trans=>{return trans.table('users').toCollection().modify(user=>{// 为已有用户添加默认邮箱if(!user.email){ user.email =`${user.name.toLowerCase()}@example.com`}})})

六、总结

IndexedDB与Dexie.js的组合为前端开发提供了强大的本地数据存储解决方案。IndexedDB作为浏览器内置的NoSQL数据库,提供了大容量存储、异步操作和事务支持等核心能力;而Dexie.js通过极简的API设计,大幅降低了IndexedDB的使用门槛。

在Vue3和React中,通过合理的封装和Hook设计,可以实现响应式的数据管理,结合实时查询功能,能够构建出真正离线优先的Web应用。无论是简单的待办事项应用,还是复杂的企业级系统,IndexedDB + Dexie.js都能提供可靠的数据存储方案。

适用场景总结

  • ✅ 需要离线功能的PWA应用
  • ✅ 存储大量结构化数据(10MB以上)
  • ✅ 需要复杂查询和索引的场景
  • ✅ 离线优先的数据同步应用
  • ❌ 简单的键值对存储(推荐localStorage)
  • ❌ 临时会话数据(推荐sessionStorage)

Read more

ROS1从入门到精通 12:导航与路径规划(让机器人自主导航)

【ROS1从入门到精通】第12篇:导航与路径规划(让机器人自主导航) 🎯 本文目标:深入学习ROS导航栈(Navigation Stack),掌握move_base框架、全局路径规划、局部路径规划、代价地图、恢复行为等核心概念,能够配置和调试完整的自主导航系统,实现机器人的智能移动。 📑 目录 1. ROS导航栈概述 2. move_base框架 3. 代价地图(Costmap) 4. 全局路径规划 5. 局部路径规划 6. 恢复行为 7. 导航配置与调优 8. 导航目标发送 9. 多机器人导航 10. 实战案例:完整导航系统 11. 总结与最佳实践 1. ROS导航栈概述 1.1 什么是ROS导航栈? ROS导航栈是一个2D导航框架,提供了从当前位置到目标位置的路径规划和执行能力。它包括:

FASTLIVO2算法解析与实战(一):SLAM领域的新标杆,如何让机器人“看得更清、跑得更稳”

FASTLIVO2算法解析与实战(一):SLAM领域的新标杆,如何让机器人“看得更清、跑得更稳”

FASTLIVO2系统概述 1. 背景介绍 1.1 传感器特性 FASTLIVO2 系统融合了三种互补的传感器:激光雷达(LiDAR)、相机(Camera)和惯性测量单元(IMU)。它们在感知方式、输出数据和环境适应性上各具特点,通过融合实现优势互补。 特性激光雷达(LiDAR)相机(Camera)IMU工作方式主动发射激光,通过反射测量距离和方位被动接收环境光,捕捉 2D 图像信息主动测量自身运动感知内容环境几何结构(深度、形状、表面)环境纹理与颜色(语义、细节、动态物体)自身运动状态(姿态、速度、加速度)数据输出3D 点云(精确深度)2D 像素矩阵(RGB 或灰度)6 自由度运动参数优势- 直接深度测量,精度高- 不受光照影响- 在结构化环境中鲁棒-

ESP32-S3 做 AI 人脸追踪机器人

用 ESP32-S3 打造会“追人”的 AI 小机器人 🤖👀 你有没有想过,一个成本不到百元的开发板,也能做出能识别人脸、自动转头盯着你看的小机器人?听起来像科幻片?但它真的可以做到——而且核心就是那块我们常见的 ESP32-S3 。 别被它的价格骗了。这颗芯片虽然只有巴掌大、几十块钱,却藏着让人惊讶的潜力:双核处理器、支持AI指令集、能接摄像头、还能驱动舵机……把这些能力串起来,就能让一个小小的机器人“睁开眼睛”,学会看世界,并且主动追踪人脸。 今天,我们就来拆解这个项目背后的完整技术链路:从如何在资源紧张的MCU上跑通AI模型,到图像采集、推理计算、再到控制机械结构闭环响应——一步步教你打造属于自己的 AI人脸追踪机器人 。 为什么选 ESP32-S3?它真能跑AI吗? 很多人第一反应是:“AI不是得靠GPU或者树莓派那种高性能设备吗?ESP32 这种微控制器也能行?” 说实话,我一开始也怀疑过 😅。但当你深入了解 ESP32-S3 的设计细节后,你会发现——它确实是为“

双模态无人机太阳能光伏红外可见光一一对应缺陷检测数据集,共650张 无人机可见光红外缺陷检测数据集 红外 + 可见光配对无人机红外可见光光伏缺陷检测数据集

双模态无人机太阳能光伏红外可见光一一对应缺陷检测数据集,共650张 无人机可见光红外缺陷检测数据集 红外 + 可见光配对无人机红外可见光光伏缺陷检测数据集

1 1 1 1 1 类别: dmjrb ns dyrb ejgdl zw yyzd ygfs ycdw dmjrb_ycdw dyrb_ycdw ✅ 一、数据集基本信息表 项目内容数据集名称无人机光伏太阳能板缺陷检测数据集(红外 + 可见光配对)总图像数量650 张(红外与可见光图像严格一一对应,共 650 对 → 1,300 张图像)模态类型双模态配对数据:• 红外热成像(Infrared)• 可见光图像(RGB)标注格式YOLO 格式(.txt 文件,适用于 YOLOv5/v8/v11 等)数据划分未明确说明,建议按 7:2: