本地存储

各类存储方式差别与局限性

localStorage/sessionStorage的优点前端

  1. localStorage拓展了cookie的4K限制
  2. localStorage会能够将第一次请求的数据直接存储到本地,这个至关于一个5M大小的针对于前端页面的数据库,相比于cookie能够节约带宽,可是这个倒是只有在高版本的浏览器中才支持的

localStorage/sessionStorage的局限web

  1. 浏览器的大小不统一,而且在IE8以上的IE版本才支持localStorage这个属性
  2. 目前全部的浏览器中都会把localStorage的值类型限定为string类型,这个在对咱们平常比较常见的JSON对象类型须要一些转换
  3. localStorage在浏览器的隐私模式下面是不可读取的
  4. localStorage本质上是对字符串的读取,若是存储内容多的话会消耗内存空间,会致使页面变卡
  5. localStorage不能被爬虫抓取到
    localStorage与sessionStorage的惟一一点区别就是localStorage属于永久性存储,而sessionStorage属于当会话结束的时候,sessionStorage中的键值对会被清空

IndexedDB 特色sql

  • IndexedDB 数据库使用key-value键值对储存数据. values 数据能够是结构很是复杂的对象,key可使对象自身的属性。你能够对对象的某个属性建立索引(index)以实现快速查询和列举排序。.key可使二进制对象
  • IndexedDB 是事务模式的数据库. 任何操做都发生在事务(transaction)中。 IndexedDB API提供了索引(indexes), 表(tables), 指针(cursors)等等, 可是全部这些必须是依赖于某种事务的。所以,你不能在事务外执行命令或者打开指针。事务(transaction)有生存周期, 在生存周期之后使用它会报错。而且,事务(transaction)是自动提交的,不能够手动提交。
  • The IndexedDB API 基本上是异步的. IndexedDB的API不经过return语句返回数据,而是须要你提供一个回调函数来接受数据。执行API时,你不以同步(synchronous)方式对数据库进行“存储”和“读取”操做,而是向数据库发送一个操做“请求”。当操做完成时,数据库会以DOM事件的方式通知你,同时事件的类型会告诉你这个操做是否成功完成。这个过程听起来会有些复杂,可是里面是有明智的缘由的。这个和XMLHttpRequest请求是相似的
  • IndexedDB数据库“请求”无处不在 咱们上边提到,数据库“请求”负责接受成功或失败的DOM事件。每个“请求”都包含onsuccess和onerror事件属性,同时你还对“事件”调用addEventListener()和removeEventListener()。“请求”还包括readyState,result和errorCode属性,用来表示“请求”的状态。result属性尤为神奇,他能够根据“请求”生成的方式变成不一样的东西,例如:IDBCursor实例、刚插入数据库的数值对应的键值(key)等。
  • IndexedDB在结果准备好以后经过DOM事件通知用户 DOM事件老是有一个类型(type)属性(在IndexedDB中,该属性一般设置为success或error)。DOM事件还有一个目标(target)属性,用来告诉事件是被谁触发的。一般状况下,目标(target)属性是数据库操做生成的IDBRequest。成功(success)事件不弹出提示而且不能撤销,错误(error)事件会弹出提示且能够撤销。这一点是很是重要的,由于除非错误事件被撤销,不然他们会终止所在的任何事务。
  • IndexedDB是面向对象的。indexedDB不是用二维表来表示集合的关系型数据库。传统的关系型数据库,你须要用到二维表来存储数据集合(每一行表明一个数据,每一列表明一个属性),indexedDB有所不一样,它要求你为一种数据建立一个对象存储(object Store),只要这种数据一个JavaScript对象便可。每一个对象存储都有一个索引(index)集合以方便查询和迭代遍历。若是你不熟悉面向对象的数据库管理系统,能够参考维基百科有关对象数据库的内容
  • indexedDB不使用结构化查询语言(SQL)。它经过索引(index)所产生的指针(cursor)来完成查询操做,从而使你能够迭代遍历到结果集合。若是你不熟悉NoSQL系统,能够参考维基百科相关文章。
  • IndexedDB遵循同源(same-origin)策略 “源”指脚本所在文档URL的域名、应用层协议和端口。每个“源”都有与其相关联的数据库。在同一个“源”内的全部数据库都有惟1、可区别的名称。

IndexedDB vs Web Storage
Web Storage使用简单字符串键值对在本地存储数据,方便灵活,可是对于大量结构化数据存储力不从心,IndexedDB是为了可以在客户端存储大量的结构化数据,而且使用索引高效检索的API。
IndexedDB的技术特色是,不须要你去写特定的sql语句来对数据进行操做,它是nosql的,数据形式使用的是json。数据库

IndexedDB里数据以对象的形式存储,每一个对象都有一个key值索引。IndexedDB里的操做都是事务性的。一种对象存储在一个objectStore里,objectStore就至关于关系数据库里的表。IndexedDB能够有不少objectStore,objectStore里能够有不少对象。每一个对象能够用key值获取。
IndexedDB vs LocalStoragejson

IndexedDB和LocalStorage都是用来在浏览器里存储数据,但它们使用不一样的技术,有不一样的用途,你须要根据本身的状况适当的选择使用哪一种。LocalStorage是用key-value键值模式存储数据,但跟IndexedDB不同的是,它的数据并非按对象形式存储。它存储的数据都是字符串形式。若是你想让LocalStorage存储对象,你须要借助JSON.stringify()能将对象变成字符串形式,再用JSON.parse()将字符串还原成对象。但若是要存储大量的复杂的数据,这并非一种很好的方案。毕竟,localstorage就是专门为小数量数据设计的,它的api是同步的。api

IndexedDB很适合存储大量数据,它的API是异步调用的。IndexedDB使用索引存储数据,各类数据库操做放在事务中执行。IndexedDB甚至还支持简单的数据类型。IndexedDB比localstorage强大得多,但它的API也相对复杂。数组

对于简单的数据,你应该继续使用localstorage,但当你但愿存储大量数据时,IndexedDB会明显的更适合,IndexedDB能提供你更为复杂的查询数据的方式。浏览器

IndexedDB vs Web SQL
WebSQL也是一种在浏览器里存储数据的技术,跟IndexedDB不一样的是,IndexedDB更像是一个NoSQL数据库,而WebSQL更像是关系型数据库,使用SQL查询数据。W3C已经再也不支持这种技术。
由于再也不支持,因此你就不要在项目中使用这种技术了。cookie

IndexedDB vs Cookies
Cookies,每次HTTP接受和发送都会传递Cookies数据,它会占用额外的流量。例如,若是你有一个10KB的Cookies数据,发送10次请求,那么,总计就会有100KB的数据在网络上传输。Cookies只能是字符串。浏览器里存储Cookies的空间有限,不少用户禁止浏览器使用Cookies。因此,Cookies只能用来存储小量的非关键的数据。网络

基本操做

localStorage/sessionStorage基本操做

(1)setItem(key,value):添加本地存储数据。两个参数,很是简单就不说了。
(2)getItem(key):经过key获取相应的Value。
(3)removeItem(key):经过key删除本地数据。
(4)clear():清空数据。

IndexedDB 基本操做

建立、打开数据库

须要根据不一样浏览器的内核,建立indexedDB对象
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB

打开一个数据库,open方法, 该方法接收两个参数:

  • dbName // 数据库名称 [string]
  • version // 数据库版本 [整型number]
var name = 'person-text', version = 1, db var request = indexedDB.open(name, version) request.onsuccess = function(event) { db = event.target.result; db.onsuccess = function(event) { console.log('数据库操做成功!') }; db.onerror = function(event) { console.error('数据库操做发生错误!', event.target.errorCode) }; console.log('打开数据库成功!') } request.onerror = function(event) { console.error('建立数据库出错') console.error('error code:', event.target.errorCode) } request.onupgradeneeded = function(event) { // 更新对象存储空间和索引 .... } 

如果本域下不存在名为 person-text 的数据库,则上述代码会建立一个名为person-text、版本号为1的数据库; 触发的事件依次为: upgradeneeded、 success.
如果已存在名为person-text的数据库, 则上述代码会打开该数据库; 只触发success/error事件,不会触发upgradeneeded事件. db是对该数据库的引用.

建立对象存储空间和索引

在key-value型数据库(如indexedDB)中, 一个数据库会有多个对象存储空间,每一个存储空间有本身的主键、索引等;
建立对象存储空间的操做通常放在建立数据库成功回调里:

request.onupgradeneeded = function(event) { // 更新对象存储空间和索引 .... var database = event.target.result var objectStore = database.createObjectStore("person", { keyPath: "id" }) objectStore.createIndex('name', 'name', { unique: true }) objectStore.createIndex('age', 'age', { unique: false }) } 

onupgradeneeded 是咱们惟一能够修改数据库结构的地方。在这里面,咱们能够建立和删除对象存储空间以及构建和删除索引。
在数据库对象database上,有如下方法可供调用:

  1. createObjectStore(storeName, configObj) 建立一个对象存储空间
  • storeName // 对象存储空间的名称 [string]
  • configObj // 该对象存储空间的配置 [object] (其中的keyPath属性值,标志对象的该属性值惟一)
  1. createIndex(indexName, objAttr, configObj) 建立一个索引
  • indexName // 索引名称 [string]
  • objAttr // 对象的属性名 [string]
  • configObj // 该索引的配置对象 [object]

数据操做(增删改查)

对数据库的操做(增删查改等)都须要经过事务来完成,事务具备三种模式:

  • readonly 只读(能够并发进行,优先使用)
  • readwrite 读写
  • versionchange 版本变动

数据库对象的transaction()方法接收两个参数:

  • storeNames // 对象存储空间,能够是对象存储空间名称的数组,也能够是单个对象存储空间名称,必传 [array|string]
  • mode // 事务模式,上面提到的三种之一,可选,默认值是readonly [string]
var transaction = db.transaction(['person'], 'readwrite') transaction.oncomplete = function(event) { console.log('事务完成!') } transaction.onerror = function(event) { console.log('事务失败!', event.target.errorCode) } transaction.onabort = function(event) { console.log('事务回滚!') } 

向数据库中增长数据
经过事务对象transaction,在objectStore()方法中指定对象存储空间,就获得了能够对该对象存储空间进行操做的对象objectStore.
向数据库中增长数据,add()方法增长的对象,如果数据库中已存在相同的主键,或者惟一性索引的键值重复,则该条数据不会插入进去

var objectStore = transaction.objectStore('person') // 指定对象存储空间 var data = [{"name": "张三", "age": "21", "sex": "男", "id": "11" }, {"name": "李四", "age": "19", "sex": "男", "id": "12" }, {"name": "王五", "age": "21", "sex": "女", "id": "13"}, {"name": "赵六", "age": "24", "sex": "男", "id": "14"}] data.forEach(function(item, index){ var request = objectStore.add(item) request.onsuccess = function(event) { console.log('插入成功!', index) console.log(event.target.result, item.id); // add()方法调用成功后result是被添加的值的键(id) } }) 

修改数据库中的数据

var objectStore = transaction.objectStore('person') objectStore.put({"name": "李四", "age": "22", "sex": "男", "id": "12" }) 

该方法与add()不一样之处在于,数据库中若存在相同主键或者惟一性索引重复,则会更新该条数据,不然插入新数据。

从数据库中删除数据

var objectStore = transaction.objectStore('person') var request = objectStore.delete('12'); // 经过键id来删除 request.onsuccess = function(event) { console.log('删除成功!'); } 

从数据中获取数据

var objectStore = transaction.objectStore('person') var request = objectStore.get('13') request.onsuccess = function(event) { console.log('获取成功!', event) } 

使用索引

在前面,咱们建立了两个索引name和age, 配置对象里面的unique属性标志该值是否惟一
如今咱们想找到name属性值为'张三'的对象,就可使用索引。

var objectStore = db.transaction('person').objectStore('person') // 打开对象存储空间 var index = objectStore.index('name') // 使用索引 var request = index.get('张三') // 建立一个查找数据的请求 request.onsuccess = function(event) { console.log('The result is:', event.target.result) } 

使用游标

使用一次索引,咱们只能获得一条数据; 若是咱们须要获得全部数据,或某一类数据,可使用游标.
获得一个能够操做游标的请求对象有两个方法:

  • openCursor(keyRange, direction)
  • openKeyCursor(keyRange, direction)
    这两个方法接收的参数同样, 两个参数都是可选的: 第一个参数是限制值得范围,第二个参数是指定游标方向
    keyRange是限定游标遍历的数据范围,经过IDBKeyRange的一些方法设置该值:
// 匹配值为Bill的数据 var lowerBoundKeyRange = IDBKeyRange.only("Bill") // 匹配全部在 "Bill" 前面的, 包括 "Bill" var lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill"); // 匹配全部在 “Bill” 前面的, 可是不须要包括 "Bill" var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true); // 匹配全部在'Donna'后面的, 可是不包括"Donna" var upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true); // 匹配全部在"Bill" 和 "Donna" 之间的, 可是不包括 "Donna" var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true); 

游标默认遍历方向是按主键从小到大,有时候咱们倒序遍历,此时能够给openCursor()方法传递第二个参数: direction: next|nextunique|prev|prevunique

游标的使用有如下几处:

  1. 在对象存储空间上使用: var cursor = objectStore.openCursor()
  2. 在索引对象上使用: var cursor = index.openCursor()
var list = []; var index = db.transaction('person').objectStore('person') index.openCursor().onsuccess = function(event) { var cursor = event.target.result if (cursor) { console.log('cursor.value:', cursor.value); list.push(cursor.value) cursor.continue() } else { console.log('list:', list) } } 
var list = [] var index = db.transaction('person').objectStore('person').index('age') index.openCursor('24').onsuccess = function(event) { var cursor = event.target.result if (cursor) { console.log('cursor.value:', cursor.value); list.push(cursor.value) cursor.continue() } else { console.log('list:', list) } } 

使用游标时,须要在成功回调里拿到result对象,判断是否取完了数据:若数据已取完,result是undefined; 若未取完,则result是个IDBCursorWithValue对象,需调用continue()方法继续取数据。 也能够根据本身需求, 对数据进行过滤。
在索引age上使用openCursor()方法时,若不传参数,则会遍历全部数据

关闭和删除数据库

关闭数据库只须要在数据库对象db上调用close()方法便可 db.close()
关闭数据库后,db对象仍然保存着该数据库的相关信息,只是没法再开启事务

删除数据库则须要使用indexedDB.deleteDatabase(dbName)方法

相关文章
相关标签/搜索