在项目开发过程中,前端需要存储大量的数据。cookie, localstorage 都有存储长度限制。
表格一览
特性 | cookie | localStorage | sessionStorage | indexedDB |
---|---|---|---|---|
数据生命周期 | 一般由服务器生成,可以设置过期时间;前端采用和js-cookie等组件也可以生成 | 除非被清理,否则一直存在;浏览器关闭还会保存在本地,但是不支持跨浏览器 | 页面关闭就清理刷新依然存在,不支持跨页面交互 | 除非被清理,否则一直存在 |
数据存储大小 | 4K | 5M | 5M | 不限制大小 |
与服务端通信 | 每次都会携带在请求的header 中,对于请求性能有影响;同时由于请求中都带有,所以也容易出现安全问题 | 不参与 | 不参与 | 不参与 |
特点 | 字符串键值对在本地存储数据 | 字符串键值对在本地存储数据 | 字符串键值对在本地存储数据 | IndexedDB 是一个非关系型数据库(不支持通过 SQL 语句操作)。可以存储大量数据,提供接口来查询,还可以建立索引,这些都是其他存储方案无法提供的能力。 |
需要一个存储容量大,支持搜索和自定义索引的前端存储方案,就选用了 。
caniuse上查看 indexedDB 支持情况,目前浏览器支持情况良好。
caniuse.com/?search=ind…
IndexedDB 属于非关系型数据库。(不支持SQL查询)
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 }); };
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); };
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); };
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); };
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); };
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); };
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); };
首先让我们 来了解 IDBKeyRange
的API
www.w3cschool.cn/javascript_…
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); };
indexedDB 并非无底洞,可以无限存储。要考虑做定期删除等功能
getAll
方法,获取指定条件的data
,再遍历data
,调用删除数据APIJavaScript
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) {};
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))