您当前的位置:首页 > 电脑百科 > 数据库 > 百科

indexedDB 才是前端存储新宠!

时间:2023-05-31 17:38:13  来源:稀土掘金  作者:叫叫技术团队

前言

在项目开发过程中,前端需要存储大量的数据。cookie, localstorage 都有存储长度限制。
表格一览

特性 cookie localStorage sessionStorage indexedDB
数据生命周期 一般由服务器生成,可以设置过期时间;前端采用和js-cookie等组件也可以生成 除非被清理,否则一直存在;浏览器关闭还会保存在本地,但是不支持跨浏览器 页面关闭就清理刷新依然存在,不支持跨页面交互 除非被清理,否则一直存在
数据存储大小 4K 5M 5M 不限制大小
与服务端通信 每次都会携带在请求的header 中,对于请求性能有影响;同时由于请求中都带有,所以也容易出现安全问题 不参与 不参与 不参与
特点 字符串键值对在本地存储数据 字符串键值对在本地存储数据 字符串键值对在本地存储数据 IndexedDB 是一个非关系型数据库(不支持通过 SQL 语句操作)。可以存储大量数据,提供接口来查询,还可以建立索引,这些都是其他存储方案无法提供的能力。

需要一个存储容量大,支持搜索和自定义索引的前端存储方案,就选用了 。
caniuse上查看 indexedDB 支持情况,目前浏览器支持情况良好。
caniuse.com/?search=ind…
image.png

IndexedDB介绍

IndexedDB 属于非关系型数据库。(不支持SQL查询)

特点:

  • 键值对储存 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JAVAScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
  • 异步 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
  • 支持事务 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
  • 同源限制 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
  • 支持二进制储存 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象。
  • 储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。储 存 在 电 脑 上 中 的 位 置 为 C:Users当 前 的 登 录 用 户AppDataLocalgoogleChromeUser DataDefaultIndexedDB

核心概念

  • 数据库:IDBDatabase 对象,数据库有版本概念,同一时刻只能有一个版本,每个域名可以建多个数据库
  • 对象仓库:IDBObjectStore 对象,类似于关系型数据库的表格
  • 索引: IDBIndex 对象,可以在对象仓库中,为不同的属性建立索引,主键建立默认索引
  • 事务: IDBTransaction 对象,增删改查都需要通过事务来完成,事务对象提供了error,abord,complete三个回调方法,监听操作结果
  • 操作请求:IDBRequest 对象
  • 指针: IDBCursor 对象
  • 主键集合:IDBKeyRange 对象,主键是默认建立索引的属性,可以取当前层级的某个属性,也可以指定下一层对象的属性,还可以是一个递增的整数

indexedDB使用

基础操作

1. 创建数据库 & 新建表和索引


 
typescript
复制代码
/* *@databaseName 数据仓库的名字 *@version 数据仓库的版本 *@databaseName 数据仓库的名字 */ var request = window.indexedDB.open('group', 1); /* *数据仓库打开失败 */ request.onerror = function(error) { console.log('IndexedDB 打开失败', error); }; /* *数据仓库打开成功 */ request.onsuccess = function(res) { console.log('IndexedDB 打开成功', res); db = res.target.result; }; /* *数据仓库升级事件(第一次新建库是也会触发,因为数据仓库从无到有算是升级了一次) */ request.onupgradeneeded = function(res) { console.log('IndexedDB 升级成功', res); db = res.target.result; db_table = db.createObjectStore('group', { keyPath: 'id' }); db_table.createIndex('indexName', 'name', { unique: false }); };

image.png

image.png

2. 新增数据


 
typescript
复制代码
/* *新建事务 *@params 数据仓库的数组 *@params 写入模式 */ var store = db.transaction(['group'], 'readwrite').objectStore('group'); /* *add方法添加数据 *@params 需要添加的数据信息 */ var request = store.add({ id: new Date().getTime(), name: '王二', age: 12, emAIl: 'XXXX@xxx.com', }); /* *添加成功 */ request.onsuccess = function(event) { console.log('数据添加成功', event); }; /* *添加失败 */ request.onerror = function(event) { console.log('数据添加失败', event); };

image.png

image.png

3. 读取数据


 
typescript
复制代码
/* *新建事务 *@params 数据仓库的数组 */ var store = db.transaction(['group']).objectStore('group'); /* *get方法获取数据 *@params 数据的主键 */ var request = store.get(1678664831491); /* *获取成功 */ request.onsuccess = function(event) { if (event.target.result) { console.log('数据获取成功', event.target.result); } else { console.log('未获取到数据'); } }; /* *获取失败 */ request.onerror = function(event) { console.log('数据获取失败', event); };

image.png

4. 更新数据


 
typescript
复制代码
/* *新建事务 *@params 数据仓库的数组 *@params 写入模式 */ var store = db.transaction(['group'], 'readwrite').objectStore('group'); /* *put方法根据主键更新数据 *@params 数据的主键 */ var request = store.put({ id: 1678664831491, name: '张一' + Math.random(), age: 24, email: 'zhangsan@example.com', }); /* *更新成功 */ request.onsuccess = function(event) { console.log('数据更新成功', event); }; /* *更新失败 */ request.onerror = function(event) { console.log('数据更新失败', event); };

未加 readwrite, 会抛错,修改数据失败

image.png
image.png

 

image.png

5. 删除数据


 
typescript
复制代码
/* *新建事务 *@params 数据仓库的数组 */ var store = db.transaction(['group'], 'readwrite').objectStore('group'); /* *delete方法删除数据 *@params 数据的主键 */ var request = store.delete(1678664831491); /* *删除成功 */ request.onsuccess = function (event) { console.log('数据删除成功',event); }; /* *删除失败 */ request.onerror = function (event) { console.log('数据删除失败',event); };

image.png
image.png

6. 使用索引


 
typescript
复制代码
/* *新建事务 *@params 数据仓库的数组 */ var store = db.transaction(['group']).objectStore('group'); /* *index方法获取索引对象 *get方法获取数据 *@params 数据的索引 */ var request = store.index('indexName').get('张四'); /* *获取成功 */ request.onsuccess = function (event) { console.log('通过索引获取数据成功',event.target.result); }; /* *获取失败 */ request.onerror = function (event) { console.log('通过索引获取数据失败',event); };

image.png

image.png

7. 获取整张表所有的data


 
typescript
复制代码
var store = db.transaction(['group']).objectStore('group'); var request = store.getAll(); /* *更新成功 */ request.onsuccess = function(event) { console.log('indexedDB getAll:', event.target.result); }; /* *更新失败 */ request.onerror = function(event) { console.log('indexedDB getAll:', event); };

image.png

8. 根据指定条件获取data

首先让我们 来了解 IDBKeyRange 的API
www.w3cschool.cn/javascript_…
image.png


 
typescript
复制代码
var store = db.transaction(['group']).objectStore('group'); // 获取id名称小于当前时间的所有data var request = store.getAll(IDBKeyRange.upperBound(+new Date())); /* *更新成功 */ request.onsuccess = function(event) { console.log('indexedDB getAll:', event.target.result); }; /* *更新失败 */ request.onerror = function(event) { console.log('indexedDB getAll:', event); };

image.png

业务中优雅使用

indexedDB 并非无底洞,可以无限存储。要考虑做定期删除等功能

1. 定期删除失效数据

1. 首先我们创建数据的时候就以时间戳+失效时间来约定id规则

image.png

2. 再通过上面基础操作的getAll方法,获取指定条件的data,再遍历data,调用删除数据API


 
JavaScript
复制代码
var store = db.transaction(['group'], 'readwrite').objectStore('group'); var request = store.getAll(IDBKeyRange.upperBound(+new Date())); /* *更新成功 */ request.onsuccess = function(event) { console.log('indexedDB getAll:', event); console.log('indexedDB getAll:', event.target.result); const data = event.target.result; data.forEach(item => { console.log('删除数据', item); const deletRequest = store.delete(item.id); /* *删除成功 */ deletRequest.onsuccess = function(event) { console.log('数据删除成功', event); }; /* *删除失败 */ deletRequest.onerror = function(event) { console.log('数据删除失败', event); }; }); }; /* *更新失败 */ request.onerror = function(event) {};

image.png

3. 我们把上述方法包装下每次打开页面,清空下失效数据。就可以实现一个定期删除失效数据的方法啦

2. 批量添加数据


 
typescript
复制代码
const TestData = [ { event: 'NE-TEST1', level: 'warning', errorCode: 200, url: 'http://www.example.com', time: '2017/11/8 下午4:53:039', isUploaded: false }, { event: 'NE-TEST2', msg: '测试2', level: 'error', errorCode: 1000, url: 'http://www.example.com', time: '2017/11/8 下午4:53:042', isUploaded: false }, { event: 'NE-TEST3', msg: '测试3', level: 'info', errorCode: 3000, url: 'http://www.example.com', time: '2017/11/8 下午4:53:043', isUploaded: false }, { event: 'NE-TEST4', mgs: '测试4', level: 'info', url: 'http://www.example.com', time: '2017/11/8 下午4:53:0423', isUploaded: false } ] /** * 添加数据 * @param {array} docs 要添加数据 * @param {string} objName 仓库名称 */ function addData (docs, objName) { if (!(docs && docs.length)) { throw new Error('docs must be a array!') } return openIndexedDB().then(db => { const tx = db.transaction([objName], 'readwrite') tx.oncomplete = e => { console.log('tx:addData onsuccess', e) return Promise.resolve(docs) } tx.onerror = e => { e.stopPropagation() console.error('tx:addData onerror', e.target.error) return Promise.reject(e.target.error) } tx.onabort = e => { console.warn('tx:addData abort', e.target) return Promise.reject(e.target.error) } const obj = tx.objectStore(objName) docs.forEach(doc => { const req = obj.add(doc) /** * NOTE: * request * 两个事件: * 1. success * 2. error */ // req.onsuccess = e => console.log('obj:addData onsuccess', e.target) req.onerror = e => { console.error('obj:addData onerror', e.target.error) } }) }) } addData(TestData, OB_NAMES.UseKeyGenerator) .then(() => addData(TestData, OB_NAMES.UseKeyPath))
作者:叫叫技术团队
链接:https://juejin.cn/post/7239259798267904059
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


Tags:indexedDB   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
indexedDB 才是前端存储新宠!
前言在项目开发过程中,前端需要存储大量的数据。cookie, localstorage 都有存储长度限制。 表格一览 特性 cookie localStorage sessionStorage indexedDB ...【详细内容】
2023-05-31  Search: indexedDB  点击:(84)  评论:(0)  加入收藏
IndexedDB 是什么
在现代浏览器的本地存储方案中,indexedDB 是一项重要的能力组成, 它是可以在浏览器端使用的本地数据库,可以存储大量数据,提供接口来查询,还可以建立索引,这些都是其他存储方案 Co...【详细内容】
2019-10-14  Search: indexedDB  点击:(1074)  评论:(0)  加入收藏
▌简易百科推荐
向量数据库落地实践
本文基于京东内部向量数据库vearch进行实践。Vearch 是对大规模深度学习向量进行高性能相似搜索的弹性分布式系统。详见: https://github.com/vearch/zh_docs/blob/v3.3.X/do...【详细内容】
2024-04-03  京东云开发者    Tags:向量数据库   点击:(4)  评论:(0)  加入收藏
原来 SQL 函数是可以内联的!
介绍在某些情况下,SQL 函数(即指定LANGUAGE SQL)会将其函数体内联到调用它的查询中,而不是直接调用。这可以带来显著的性能提升,因为函数体可以暴露给调用查询的规划器,从而规划器...【详细内容】
2024-04-03  红石PG  微信公众号  Tags:SQL 函数   点击:(3)  评论:(0)  加入收藏
如何正确选择NoSQL数据库
译者 | 陈峻审校 | 重楼Allied Market Research最近发布的一份报告指出,业界对于NoSQL数据库的需求正在持续上升。2022年,全球NoSQL市场的销售额已达73亿美元,预计到2032年将达...【详细内容】
2024-03-28    51CTO  Tags:NoSQL   点击:(13)  评论:(0)  加入收藏
为什么数据库连接池不采用 IO 多路复用?
这是一个非常好的问题。IO多路复用被视为是非常好的性能助力器。但是一般我们在使用DB时,还是经常性采用c3p0,tomcat connection pool等技术来与DB连接,哪怕整个程序已经变成以...【详细内容】
2024-03-27  dbaplus社群    Tags:数据库连接池   点击:(12)  评论:(0)  加入收藏
八个常见的数据可视化错误以及如何避免它们
在当今以数据驱动为主导的世界里,清晰且具有洞察力的数据可视化至关重要。然而,在创建数据可视化时很容易犯错误,这可能导致对数据的错误解读。本文将探讨一些常见的糟糕数据可...【详细内容】
2024-03-26  DeepHub IMBA  微信公众号  Tags:数据可视化   点击:(6)  评论:(0)  加入收藏
到底有没有必要分库分表,如何考量的
关于是否需要进行分库分表,可以根据以下考量因素来决定: 数据量和负载:如果数据量巨大且负载压力较大,单一库单一表可能无法满足性能需求,考虑分库分表。 数据增长:预估数据增长...【详细内容】
2024-03-20  码上遇见你  微信公众号  Tags:分库分表   点击:(13)  评论:(0)  加入收藏
在 SQL 中写了 in 和 not in,技术总监说要炒了我……
WHY?IN 和 NOT IN 是比较常用的关键字,为什么要尽量避免呢?1、效率低项目中遇到这么个情况:t1表 和 t2表 都是150w条数据,600M的样子,都不算大。但是这样一句查询 ↓select *...【详细内容】
2024-03-18  dbaplus社群    Tags:SQL   点击:(5)  评论:(0)  加入收藏
应对慢SQL的致胜法宝:7大实例剖析+优化原则
大促备战,最大的隐患项之一就是慢SQL,对于服务平稳运行带来的破坏性最大,也是日常工作中经常带来整个应用抖动的最大隐患,在日常开发中如何避免出现慢SQL,出现了慢SQL应该按照什...【详细内容】
2024-03-14  京东云开发者    Tags:慢SQL   点击:(4)  评论:(0)  加入收藏
过去一年,我看到了数据库领域的十大发展趋势
作者 | 朱洁策划 | 李冬梅过去一年,行业信心跌至冰点2022 年中,红衫的一篇《适应与忍耐》的报告,对公司经营提出了预警,让各个公司保持现金流,重整团队,想办法增加盈利。这篇报告...【详细内容】
2024-03-12    InfoQ  Tags:数据库   点击:(26)  评论:(0)  加入收藏
SQL优化的七个方法,你会哪个?
一、插入数据优化 普通插入:在平时我们执行insert语句的时候,可能都是一条一条数据插入进去的,就像下面这样。INSERT INTO `department` VALUES(1, '研发部(RD)', &#39...【详细内容】
2024-03-07  程序员恰恰  微信公众号  Tags:SQL优化   点击:(19)  评论:(0)  加入收藏
相关文章
站内最新
站内热门
站内头条