内容简介:在开始之前,我们先简单梳理一下浏览器存储的几种方式(详见:point_right:浏览器存储方式)cookie 和 webStorage 存储数据格式仅支持 String,存储时需要借助一般来说,我们更推荐使用 webStroage,但其存储大小有限、数据存储仅支持 String 格式、不提供搜索功能,不能建立自定义的索引。因此,需要一种新的解决方案,这就是
IndexedDB 诞生背景
在开始之前,我们先简单梳理一下浏览器存储的几种方式(详见:point_right:浏览器存储方式)
| 会话期 Cookie | 持久性 Cookie | sessionStorage | localStorage | indexedDB | WebSQL | |
|---|---|---|---|---|---|---|
| 存储大小 | 4kb | 4kb | 2.5~10 MB | 2.5~10 MB | >250MB | 已废弃 |
| 失效时间 | 浏览器关闭自动清除 | 设置过期时间,到期后清除 | 浏览器关闭后清除 | 永久保存(除非手动清除) | >手动更新或删除 | 已废弃 |
| 与服务端交互 | 有 | 有 | 无 | 无 | 无 | 已废弃 |
| 访问策略 | 符合同源策略可以访问 | 符合同源策略可以访问 | 符合同源策略可以访问 | 即使同源也不可相互访问 | 符合同源策略可以访问 | 已废弃 |
-
cookie:存储大小有限(4kb)、与服务端有交互,安全性较低、原生接口不友好,需要自己封装、能设置过期时间 -
webStorage:存储空间较大,但有上限(2.5~10MB,各家浏览器不同)、与服务端无交互,安全性高、原生接口友好,数据操作比 cookie 方便
2.1localStorage:持久化本地存储,关闭浏览器重新打开数据依然存在(除非手动删除数据)
2.2sessionStorage:浏览器窗口关闭后销毁数据
cookie 和 webStorage 存储数据格式仅支持 String,存储时需要借助 JSON.stringify()
将 JSON 对象转化为字符串,读取时需要借助 JSON.parse()
将字符串转化为 JSON 对象
一般来说,我们更推荐使用 webStroage,但其存储大小有限、数据存储仅支持 String 格式、不提供搜索功能,不能建立自定义的索引。因此,需要一种新的解决方案,这就是 IndexedDB
诞生的背景。
一、什么是 IndexedDB ?
通俗地说,IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage 所不具备的。就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。
从 DB(Data Base) 可以看出它是一个数据库。常用的数据库有两种类型:
-
关系型数据库:数据存储在表中,使用 sql 语句操作数据库,如:
MySQL、Oracle、WebSQL(已废弃) -
非关系型数据库:数据集作为 JSON 对象存储,不需要写sql 语句,如:
Redis、MongoDB、IndexedDB
IndexedDB 是非关系型数据库,不需要写 sql 语句进行数据库操作,数据格式可使用 JSON 对象。
特性:
- 存储空间大:没有存储上限,一般来说不小于 250M
-
存储格式多样:
对象仓库 (object store)
- 异步操作:性能更强。防止进行大量数据读写时,拖慢网页(localStorage 的操作是同步的)
- 同源限制:每一个数据库对应一个域名。只能访问自身域名下的数据库,不能跨域访问
- 支持事务:在一系列操作步骤之中,如果有一步失败,那么整个事务就都会取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况
二、适用场景
- cookie:短期登陆,例如:token 会过期,需要设置过期时间,过期后重新换取 token
- sessionStorage:敏感账号一次性登录
- localStorage:长期登录
- indexedDB:存储大量结构化数据数据
对于简单的数据,应该继续使用 localStorage;对于大量结构化数据,indexedDB 会更适合。当然如果你需要设置过期时间的短期存储,还是使用 cookie 存储吧。
三、开始使用
基本步骤:
- 打开(创建)数据库,并开始一个事务
- 创建一个 object store
- 构建一个请求来执行一些数据库操作,像增加或提取数据等
- 通过监听正确类型的 DOM 事件以等待操作完成
- 在操作结果上进行一些操作(可以在 request 对象中找到)
(1) 基础调用
(2)封装
<script>
var myDB = {
name: 'school', // 数据库名
version: 1, // 数据库版本号
db: null,
ojstore: {
name: 'teachers', // 存储空间表的名字
keypath: 'id', // 主键
indexKey: 'age' // 年龄索引
}
}
var INDEXDB = {
indexedDB: window.indexedDB || window.webkitindexedDB,
IDBKeyRange: window.IDBKeyRange || window.webkitIDBKeyRange, // 键范围
// 打开或创建数据库,建立对象存储空间 ObjectStore
openDB: function (dbname, dbversion) {
var that = this
var version = dbversion || 1
var request = that.indexedDB.open(dbname, version)
request.onerror = function (e) {
console.log(e.currentTarget.error.message)
}
request.onsuccess = function (e) {
myDB.db = e.target.result
console.log('成功建立并打开数据库:' + myDB.name + 'version' + dbversion)
}
request.onupgradeneeded = function (e) {
var db = e.target.result
var transaction = e.target.transaction
var store
if (!db.objectStoreNames.contains(myDB.ojstore.name)) {
//没有该对象空间时创建该对象空间
store = db.createObjectStore(myDB.ojstore.name, {
keyPath: myDB.ojstore.keypath
})
console.log('成功建立对象存储空间:' + myDB.ojstore.name)
that.storeIndex(store, myDB.ojstore.indexKey)
}
}
},
// 删除数据库
deletedb: function (dbname) {
var that = this
that.indexedDB.deleteDatabase(dbname)
console.log(dbname + '数据库已删除')
},
// 关闭数据库
closeDB: function (db) {
db.close()
console.log('数据库已关闭')
},
// 添加数据,重复添加会报错
addData: function (db, storename, data) {
var store = db.transaction(storename, 'readwrite').objectStore(storename)
var request
for(var i = 0; i < data.length; i++) {
request = store.add(data[i])
request.onerror = function() {
console.error('add添加数据库中已有该数据')
}
request.onsuccess = function() {
console.log('add添加数据已存入数据库')
}
}
},
// 通过游标查询记录
cursorGetData: function (db, storename, keyRange) {
var keyRange = keyRange || ''
var store = db.transaction(storename, 'readwrite').objectStore(storename)
var request = store.openCursor(keyRange)
request.onsuccess = function (e) {
var cursor = e.target.result
if (cursor) { // 必须要检查
console.log(cursor)
cursor.continue() // 遍历了存储对象中的所有内容
} else{
console.log('游标查询结束')
}
}
},
// 通过索引游标查询记录
cursorGetDataByIndex: function (db, storename, keyRange) {
var keyRange = keyRange || ''
var store = db.transaction(storename, 'readwrite').objectStore(storename)
var request = store.index('age').openCursor(keyRange)
request.onsuccess = function (e) {
console.log('游标开始查询')
var cursor = e.target.result
if (cursor) {//必须要检查
console.log(cursor)
cursor.continue()//遍历了存储对象中的所有内容
} else {
console.log('游标查询结束')
}
}
},
// 通过游标更新记录
cursorUpdateData: function (db, storename) {
var keyRange = keyRange || ''
var store = db.transaction(storename,'readwrite').objectStore(storename)
var request = store.openCursor()
request.onsuccess = function (e) {
console.log('游标开始查询')
var cursor = e.target.result
var value, updateRequest
if (cursor) { // 必须要检查
console.log(cursor)
if (cursor.key === 1002) {
console.log('游标开始更新')
value = cursor.value
value.age = 38
updateRequest = cursor.update(value)
updateRequest.onerror = function () {
console.log('游标更新失败')
}
updateRequest.onsuccess = function () {
console.log('游标更新成功')
}
} else {
cursor.continue()
}
}
}
},
// 通过游标删除记录
cursorDeleteData: function (db, storename) {
var keyRange = keyRange || ''
var store = db.transaction(storename, 'readwrite').objectStore(storename)
var request = store.openCursor()
request.onsuccess = function (e) {
var cursor = e.target.result
var value, deleteRequest
if (cursor) {
if (cursor.key === 1003) {
deleteRequest = cursor.delete() // 请求删除当前项
deleteRequest.onerror = function () {
console.log('游标删除该记录失败')
}
deleteRequest.onsuccess = function () {
console.log('游标删除该记录成功')
}
} else {
cursor.continue()
}
}
}
},
// 创建索引
storeIndex: function (store, indexKey) {
var index = store.createIndex(indexKey, indexKey, {
unique:false
})
console.log('创建索引' + indexKey + '成功')
}
}
var teachers = [{
id:1001,
name:'Byron',
age:21
}, {
id:1002,
name:'Frank',
age:22
}, {
id:1003,
name:'Aaron',
age:23
}, {
id:1004,
name:'Aaron',
age:24
}, {
id:1005,
name:'Byron',
age:24
}, {
id:1006,
name:'Frank',
age:30
}, {
id:1007,
name:'Aaron',
age:26
}, {
id:1008,
name:'Aaron',
age:27
}]
INDEXDB.openDB(myDB.name, myDB.version)
setTimeout(function() {
// 添加数据
INDEXDB.addData(myDB.db, myDB.ojstore.name, teachers)
// 游标更新数据id1002更新其age为38
INDEXDB.cursorUpdateData(myDB.db, myDB.ojstore.name)
// 游标删除id为1003的数据
// INDEXDB.cursorDeleteData(myDB.db, myDB.ojstore.name)
// 关闭数据库
// INDEXDB.closeDB(myDB.db)
// 删除数据库
// INDEXDB.deletedb(myDB.db)
/*
*游标键范围方法调用
*/
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange
// 查找1004对象
// var onlyKeyRange = IDBKeyRange.only(1004)
// INDEXDB.cursorGetData(myDB.db, myDB.ojstore.name, onlyKeyRange)
// 查找从1004对象开始
// var lowerBoundKeyRange = IDBKeyRange.lowerBound(1004)
// INDEXDB.cursorGetData(myDB.db, myDB.ojstore.name, lowerBoundKeyRange)
// 查找从1004对象开始不包括1004
// var lowerBoundKeyRangeTrue = IDBKeyRange.lowerBound(1004, true)
// INDEXDB.cursorGetData(myDB.db, myDB.ojstore.name, lowerBoundKeyRangeTrue)
// 查找到1004对象结束
// var upperBoundKeyRange = IDBKeyRange.upperBound(1004)
// INDEXDB.cursorGetData(myDB.db, myDB.ojstore.name, upperBoundKeyRange)
// 查找到1004对象结束不包括1004
// var upperBoundKeyRangeTrue = IDBKeyRange.upperBound(1004, true)
// INDEXDB.cursorGetData(myDB.db, myDB.ojstore.name, upperBoundKeyRangeTrue)
// 查找到1002到1004对象
// var boundKeyRange = IDBKeyRange.bound(1002, 1004)
// INDEXDB.cursorGetData(myDB.db, myDB.ojstore.name, boundKeyRange)
// 查找到1002到1004对象不包括1002
// var boundKeyRangeLowerTrue = IDBKeyRange.bound(1002, 1004, true)
// INDEXDB.cursorGetData(myDB.db, myDB.ojstore.name, boundKeyRangeLowerTrue)
// 查找到1002到1004对象包括1002不包括1004
// var boundKeyRangeUpperTrue = IDBKeyRange.bound(1002, 1004, false, true)
// INDEXDB.cursorGetData(myDB.db, myDB.ojstore.name, boundKeyRangeUpperTrue)
// 查找到1002到1004对象不包括1002不包括1004
// var boundKeyRangeLTUT = IDBKeyRange.bound(1002, 1004, true, true)
// INDEXDB.cursorGetData(myDB.db, myDB.ojstore.name, boundKeyRangeLTUT)
/*
*存储键游标查询与索引键游标查询对比
*/
// 存储键游标查询
// var onlyKeyRange = IDBKeyRange.only(1004)
// INDEXDB.cursorGetData(myDB.db, myDB.ojstore.name, onlyKeyRange)
// 索引键游标查询
// var onlyKeyRange = IDBKeyRange.only(30)
// INDEXDB.cursorGetDataByIndex(myDB.db, myDB.ojstore.name, onlyKeyRange)
}, 1000)
</script>
(3)Dexie.js
Dexie.js 是 indexedDB 封装 SDK,API 简洁强大、简单而强壮的错误处理。
官方文档: https://dexie.org/
<!doctype html>
<html>
<head>
<!-- Include Dexie -->
<script src="https://unpkg.com/dexie@latest/dist/dexie.js"></script>
<script>
//
// Define your database
var db = new Dexie("student_database");
db.version(1).stores({
students: 'name'
});
//
// Put some data into it
//
var data = {
name: "Byron",
shoeSize: 24
}
db.students.put(data).then (function (){
//
// Then when data is stored, read from it
//
return db.students.get('Nicolas');
}).then(function (student) {
//
// Display the result
//
alert ("Nicolas has shoe size " + student.shoeSize);
}).catch(function(error) {
//
// Finally don't forget to catch any error
// that could have happened anywhere in the
// code blocks above.
//
alert ("Ooops: " + error);
});
</script>
</head>
</html>
参考文章:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Hit Refresh
Satya Nadella、Greg Shaw / HarperBusiness / 2017-9-26 / USD 20.37
Hit Refresh is about individual change, about the transformation happening inside of Microsoft and the technology that will soon impact all of our lives—the arrival of the most exciting and disruptive......一起来看看 《Hit Refresh》 这本书的介绍吧!