龙空技术网

忘记 localStorage 吧,indexedDB 才是前端存储新宠!

程序员詹姆斯 5320

前言:

当前你们对“页面信息读取失败”大约比较关心,姐妹们都需要知道一些“页面信息读取失败”的相关文章。那么小编也在网上收集了一些对于“页面信息读取失败””的相关文章,希望你们能喜欢,大家快快来学习一下吧!

前言

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

表格一览

特性

cookie

localStorage

sessionStorage

indexedDB

数据生命周期

一般由服务器生成,可以设置过期时间;前端采用和js-cookie等组件也可以生成

除非被清理,否则一直存在;浏览器关闭还会保存在本地,但是不支持跨浏览器

页面关闭就清理刷新依然存在,不支持跨页面交互

除非被清理,否则一直存在

数据存储大小

4K

5M

5M

不限制大小

与服务端通信

每次都会携带在请求的header 中,对于请求性能有影响;同时由于请求中都带有,所以也容易出现安全问题

不参与

不参与

不参与

特点

字符串键值对在本地存储数据

字符串键值对在本地存储数据

字符串键值对在本地存储数据

IndexedDB 是一个非关系型数据库(不支持通过 SQL 语句操作)。可以存储大量数据,提供接口来查询,还可以建立索引,这些都是其他存储方案无法提供的能力。

需要一个存储容量大,支持搜索和自定义索引的前端存储方案,就选用了 。

caniuse上查看 indexedDB 支持情况,目前浏览器支持情况良好。

caniuse.com/?search=ind…

IndexedDB介绍

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

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

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);};

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);};

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, 会抛错,修改数据失败

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);};

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);};

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);};

8. 根据指定条件获取data

首先让我们 来了解 IDBKeyRange 的API

typescript复制代码var store = db.transaction(['group']).objectStore('group');// 获取id名称小于当前时间的所有datavar 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);};

业务中优雅使用

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

1. 定期删除失效数据1. 首先我们创建数据的时候就以时间戳+失效时间来约定id规则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) {};
3. 我们把上述方法包装下每次打开页面,清空下失效数据。就可以实现一个定期删除失效数据的方法啦2. 批量添加数据
typescript复制代码const TestData = [    {      event: 'NE-TEST1',      level: 'warning',      errorCode: 200,      url: ';,      time: '2017/11/8 下午4:53:039',      isUploaded: false    },    {      event: 'NE-TEST2',      msg: '测试2',      level: 'error',      errorCode: 1000,      url: ';,      time: '2017/11/8 下午4:53:042',      isUploaded: false    },    {      event: 'NE-TEST3',      msg: '测试3',      level: 'info',      errorCode: 3000,      url: ';,      time: '2017/11/8 下午4:53:043',      isUploaded: false    },    {      event: 'NE-TEST4',      mgs: '测试4',      level: 'info',      url: ';,      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))
结尾一些封装好的库localforage 推荐 ⭐️⭐️⭐️⭐️⭐️ (我们当前业务就用的这个~)

和localsotrage使用保持一致,更适合前端使用

还在用localStorage?快来试试localForage吧! - 掘金

IndexedDBWrapper 推荐 ⭐️⭐️⭐️思考我们还可以用indexedDB做什么1. 用户使用日志收集在做一些前端electron应用,webApp,我们可以定义一个log日志库,来收集用户日志,遇到问题时,可以让用户,打包上传到日志库,排查跟进解决用户反馈问题。定义日志上报结构

javascript复制代码// 定义log基本结构const LogItem = {	level: 'log' | 'info' | 'error' ...,  tag: 'request' | 'system' | ‘video’ | 'audio' | 'domClick' ... ,	msg: ...,  // any  date: +new Date(),	...}
导出所有数据,并上传

此处就可以用上面的 getAll 方法,获取该表所有数据,生成json打包上传到自己公司的日志库。

2. request层封装,对不长更新接口缓存

封装request方法,缓存请求接口,物理缓存数据~让页面接口数据加载飞起来

3. 大文件上传,分片,避免网络失败,刷新页面等导致中断问题

文件切片后先存储到indexedDB库,动态更新上传状态,异常状况可取出再继续定位到未上传的切片继续上传

原文链接:

标签: #页面信息读取失败