-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
63 lines (38 loc) · 25.6 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>沈琪云</title>
<link href="/atom.xml" rel="self"/>
<link href="sqyun.github.io/"/>
<updated>2018-05-30T13:49:47.764Z</updated>
<id>sqyun.github.io/</id>
<author>
<name>沈琪云</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>前端IndexedDB 存储方案</title>
<link href="sqyun.github.io/2018/05/30/%E5%89%8D%E7%AB%AF%20indexedDB%20%E5%AD%98%E5%82%A8%E6%96%B9%E6%A1%88/"/>
<id>sqyun.github.io/2018/05/30/前端 indexedDB 存储方案/</id>
<published>2018-05-30T13:05:00.000Z</published>
<updated>2018-05-30T13:49:47.764Z</updated>
<content type="html"><![CDATA[<p><strong> 前端IndexedDB 存储方案:</strong> <excerpt in="" index="" |="" 首页摘要=""><br>IndexedDB 是一种使用浏览器存储大量数据的方法.它创造的数据可以被查询,并且可以离线使用. IndexedDB对于那些需要存储大量数据,或者是需要离线使用的程序是非常有效的解决方法. — MDN<br><a id="more"></a></excerpt></p><p><the rest="" of="" contents="" |="" 余下全文=""><br>我们都知道在前端开发当中,有时会因为某些需求,要将一些数据存储在前端本地当中.比如说:为了优化性能,将一些常用的数据存在本地,这样以后需要的时候直接从本地拿,不需要再向后端进行请求.还有就是为了防止CSRF攻击,后端给前端一个token,前端就需要将这个token存在本地.之后每次请求都需要带上这个token.等等不一而足.</the></p><p> 而这些需求就不油避免的造就一个前端的发展方向–前端存储</p><p> 在前端的’上古时代’里,我们前端想要存储数据,只有一种方式,那就是Cookie.但是Cookie虽然可以做前端存储方案,但是却也有着很多局限性.首先它的存储空间大小只有4K,其次它的存储有效时间有限制,然后存在Cookie中的数据,在你每次进行请求的时候都会将它带上.使得每次的请求数据都会无意义的增大.最后,也是最重要的一点.Cookie设计之初就不是就是让我们前端存数据用的.它只是为了让网站验证用户身份用的.至于Cookie的本地存储功能只是它的一个手段而已.关于这点你们可以看下我的另外一篇文章—在HTML5的时代,重新认识Cookie</p><p> 综上所述,使用Cookie作为前端存储有这许多缺点,所以经过前端社区的不断努力,在HTML5中有了真正的前端存储方案Web Storage.它分为两种,一种是永久存储的localStorage,一种是会话期间存储的sessionStorage.对比Cookie,Web Storage的优势很明显:</p><p>存储空间更大,有5M大小<br>在浏览器发送请求是不会带上web Storage里的数据<br>更加友好的API<br>可以做永久存储(localStorage).<br> 这一切看起来很完美,但是随着前端的不断发展,web Storage也有了一些不太合适的地方:</p><p>随着web应用程序的不断发展,5M的存储大小对于一些大型的web应用程序来说有些不够<br>web Storage只能存储string类型的数据.对于Object类型的数据只能先用JSON.stringify()转换一下在存储.<br> 基于上述原因,前端社区又提出了浏览器数据库存储这个概念.而Web SQL Database和indexedDB(索引数据库)是对这个概念的实现.其中Web SQL Database在目前来说基本已经被放弃.所以目前主流的浏览器数据库的实现就是indexedDB(索引数据库).也就是我们要介绍的 新一代的前端存储方案–indexedDB</p><h2 id="什么是-indexedDB"><a href="#什么是-indexedDB" class="headerlink" title="什么是 indexedDB"></a>什么是 indexedDB</h2><p>IndexedDB 是一种使用浏览器存储大量数据的方法.它创造的数据可以被查询,并且可以离线使用. IndexedDB对于那些需要存储大量数据,或者是需要离线使用的程序是非常有效的解决方法. — MDN<br> 上面是MDN上对于IndexedDB的介绍.其简单而言,indexedDB就是一个基于事务操作的key-value型数前端数据库.其API大多是异步的</p><h2 id="indexedDB的使用"><a href="#indexedDB的使用" class="headerlink" title="indexedDB的使用"></a>indexedDB的使用</h2><p>创建一个indexedDB数据库<br><figure class="highlight plain"><figcaption><span>request </span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">request.addEventListener('success', e => {</span><br><span class="line"> console.log('连接数据库成功');</span><br><span class="line">});</span><br><span class="line">request.addEventListener('error', e => {</span><br><span class="line"> console.log('连接数据库失败');</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><p> 在上面代码中我们使用indexedDB.open()创建一个indexedDB数据库.open()方法接受可以接受两个参数.第一个是数据库名,第二个是数据库的版本号.同时返回一个IDBOpenDBRequest对象用于操作数据库.其中对于open()的第一个参数数据库名,open()会先去查找本地是否已有这个数据库,如果有则直接将这个数据库返回,如果没有,则先创建这个数据库,再返回.对于第二个参数版本号,则是一个可选参数,如果不传,默认为1.但如果传入就必须是一个整数.</p><p> 在通过对indexedDB.open()方法拿到一个数据库对象IDBOpenDBRequest我们可以通过监听这个对象的success事件和error事件来执行相应的操作.</p><h2 id="创建一个对象仓库"><a href="#创建一个对象仓库" class="headerlink" title="创建一个对象仓库"></a>创建一个对象仓库</h2><p> 再有了一个数据库之后,我们获取就想要去存储数据了,但是单只有数据库还不够,我们还需要有对象仓库(object store).对象仓库(object store)是indexedDB数据库的基础,其类似于MySQL中表的概念.</p><p>要创建一个对象仓库必须在upgradeneeded事件中,而upgradeneeded事件只会在版本号更新的时候触发.这是因为indexedDB API中不允许数据库中的数据仓库在同一版本中发生变化<br><figure class="highlight plain"><figcaption><span>request </span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">request.addEventListener('upgradeneeded', e => {</span><br><span class="line"> const db = e.target.result;</span><br><span class="line"> const store = db.createObjectStore('Users', {</span><br><span class="line"> keyPath: 'userId',</span><br><span class="line"> autoIncrement: false</span><br><span class="line"> });</span><br><span class="line"> console.log('创建对象仓库成功');</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><p> 在上述代码中我们监听upgradeneeded事件,并在这个事件触发时使用createObjectStore()方法创建了一个对象仓库.createObjectStore()方法接受两个参数,第一个是对象仓库的名字,在同一数据库中,仓库名不能重复.第二个是可选参数.用于指定数据的主键,以及是否自增主键.</p><h2 id="创建事务"><a href="#创建事务" class="headerlink" title="创建事务"></a>创建事务</h2><p> OK现在我们有了数据库和对象仓库了,我们是否就可以存储数据了了.很抱歉,还是不行.我们还差最后一样东西—-事务.</p><h2 id="什么是事务"><a href="#什么是事务" class="headerlink" title="什么是事务"></a>什么是事务</h2><p>一个数据库事务通常包含了一个序列的对数据库的读/写操作。它的存在包含有以下两个目的<br> 上面是维基百科上对数据库事务的解释.简单来说事务就是用来保证数据库操作要么全部成功,要么全部失败的一个限制.比如,在修改多条数据时,前面几条已经成功了.,在中间的某一条是失败了.那么在这时,如果是基于事务的数据库操作,那么这时数据库就应该重置前面数据的修改,放弃后面的数据修改.直接返回错误,一条数据也不修改.</p><p><pre>const request = indexedDB.open(‘myDatabase’, 3);<br>request.addEventListener(‘success’, e => {<br> const db = e.target.result;<br> const tx = db.transaction(‘Users’, ‘readwrite’);<br>});<br></pre><br>上述代码中我们使用transaction()来创建一个事务.transaction()接受两个参数,第一个是你要操作的对象仓库名称,第二个是你创建的事务模式.传入 readonly时只能对对象仓库进行读操作,无法写操作.可以传入readwrite进行读写操作.</p><h2 id="操作数据"><a href="#操作数据" class="headerlink" title="操作数据"></a>操作数据</h2><p> 好了现在有了数据库,对象仓库,事务之后我们终于可以存储数据了.</p><p>add() : 增加数据。接收一个参数,为需要保存到对象仓库中的对象。<br>put() : 增加或修改数据。接收一个参数,为需要保存到对象仓库中的对象。<br>get() : 获取数据。接收一个参数,为需要获取数据的主键值。<br>delete() : 删除数据。接收一个参数,为需要获取数据的主键值。<br>add 和 put 的作用类似,区别在于 put 保存数据时,如果该数据的主键在数据库中已经有相同主键的时候,则会修改数据库中对应主键的对象,而使用 add 保存数据,如果该主键已经存在,则保存失败。</p><h2 id="添加数据"><a href="#添加数据" class="headerlink" title="添加数据"></a>添加数据</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">const request = indexedDB.open('myDatabase', 3);</span><br><span class="line">request.addEventListener('success', e => {</span><br><span class="line"> const db = e.target.result;</span><br><span class="line"> const tx = db.transaction('Users', 'readwrite');</span><br><span class="line"> const store = tx.objectStore('Users');</span><br><span class="line"> const reqAdd = store.add({</span><br><span class="line"> 'userId': 1,</span><br><span class="line"> 'userName': '李白',</span><br><span class="line"> 'age': 24</span><br><span class="line"> });</span><br><span class="line"> reqAdd.addEventListener('success', e => {</span><br><span class="line"> console.log('保存成功')</span><br><span class="line"> })</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h2 id="获取数据"><a href="#获取数据" class="headerlink" title="获取数据"></a>获取数据</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">const request = indexedDB.open('myDatabase', 3);</span><br><span class="line">request.addEventListener('success', e => {</span><br><span class="line"> const db = e.target.result;</span><br><span class="line"> const tx = db.transaction('Users', 'readwrite');</span><br><span class="line"> const store = tx.objectStore('Users');</span><br><span class="line"> const reqGet = store.get(1);</span><br><span class="line"> reqGet.addEventListener('success', e => {</span><br><span class="line"> console.log(this.result.userName);</span><br><span class="line"> })</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h2 id="删除数据"><a href="#删除数据" class="headerlink" title="删除数据"></a>删除数据</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">const request = indexedDB.open('myDatabase', 3);</span><br><span class="line">request.addEventListener('success', e => {</span><br><span class="line"> const db = e.target.result;</span><br><span class="line"> const tx = db.transaction('Users', 'readwrite');</span><br><span class="line"> const store = tx.objectStore('Users');</span><br><span class="line"> const reqDelete = store.delete(1);</span><br><span class="line"> reqDelete.addEventListener('success', e => {</span><br><span class="line"> console.log('删除数据成功');</span><br><span class="line"> })</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h2 id="使用游标"><a href="#使用游标" class="headerlink" title="使用游标"></a>使用游标</h2><p> 在上面当中我们使用get()方法传入一个主键来获取数据,但是这样只能够获取到一条数据.如果我们想要获取多条数据了怎么办.我们可以使用游标,来获取一个区间内的数据.</p><p> 要使用游标,我们需要使用对象仓库上的openCursor()方法创建币打开.openCursor()方法接受两个参数.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openCursor(range?: IDBKeyRange | number | string | Date | IDBArrayKey, direction?: IDBCursorDirection): IDBRequest;</span><br></pre></td></tr></table></figure></p><p> 第一个是范围,范围可以是一个IDBKeyRange对象.用以下方式创建.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">var boundRange = IDBKeyRange.bound(1, 10, false, false);</span><br><span class="line">var onlyRange = IDBKeyRange.only(1);</span><br><span class="line">var lowerRange = IDBKeyRange.lowerBound(1, false);</span><br><span class="line">var upperRange = IDBKeyRange.upperBound(10, false);</span><br></pre></td></tr></table></figure></p><p> 第二个参数是方向.主要有一下几种</p><p>next : 游标中的数据按主键值升序排列,主键值相等的数据都被读取<br>nextunique : 游标中的数据按主键值升序排列,主键值相等只读取第一条数据<br>prev : 游标中的数据按主键值降序排列,主键值相等的数据都被读取<br>prevunique : 游标中的数据按主键值降序排列,主键值相等只读取第一条数据<br> 下面让我们来看一个完整的例子<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">const request = indexedDB.open('myDatabase', 4);</span><br><span class="line">request.addEventListener('success', e => {</span><br><span class="line"> const db = e.target.result;</span><br><span class="line"> const tx = db.transaction('Users', 'readwrite');</span><br><span class="line"> const store = tx.objectStore('Users');</span><br><span class="line"> const range = IDBKeyRange.bound(1, 10);</span><br><span class="line"> const req = store.openCursor(range, 'next');</span><br><span class="line"> req.addEventListener('success', e => {</span><br><span class="line"> const cursor = this.result;</span><br><span class="line"> if (cursor) {</span><br><span class="line"> console.log(cursor.value.userName);</span><br><span class="line"> cursor.continue();</span><br><span class="line"> } else {</span><br><span class="line"> console.log('检索结束');</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><p> 在上面的代码中如果检索到符合条件的数据时,我们可以:</p><p>使用cursor.value拿到数据.<br>使用cursor.updata()更新数据.<br>使用cursor.delete()删除数据.<br>使用cursor.continue()读取下一条数据.</p><h2 id="索引"><a href="#索引" class="headerlink" title="索引"></a>索引</h2><p> 在上面代码中我们获取数据都是用的主键.但是,在很多情况下我们并不知道我们需要数据的主键是什么,我们知道一个大概的条件.比如说年龄大于20岁的用户.这个时候我们就需要用到索引.以便有条件的查找.</p><h2 id="创建索引"><a href="#创建索引" class="headerlink" title="创建索引"></a>创建索引</h2><p> 我们使用对象仓库的createIndex()方法来创建一个索引.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">createIndex(name: string, keyPath: string | string[], optionalParameters?: IDBIndexParameters): IDBIndex;</span><br></pre></td></tr></table></figure><p>createIndex()方法接收三个参数:</p><p>第一个参数name是索引名,不能重复.<br>第二个参数keyPath是你要在存储对象上的那个属性上建立索引,可以是一个单个的key值,也可以是一个包含key值集合的数组.<br>第三个参数optionalParameters是一个可选的对象参数{unique, multiEntry}<br>unique: 用来指定索引值是否可以重复,为true代表不能相同,为false时代表可以相同<br>multiEntry: 当第二个参数keyPath为一个数组时.如果multiEntry是true,则会以数组中的每个元素建立一条索引.如果是false,则以整个数组为keyPath值,添加一条索引.<br> 下面让我们来看一个完整的例子,我们建立一条用户年龄的索引.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">const request = indexedDB.open('myDatabase', 5);</span><br><span class="line">request.addEventListener('upgradeneeded', e => {</span><br><span class="line"> const db = e.target.result;</span><br><span class="line"> const store = db.createObjectStore('Users', {</span><br><span class="line"> keyPath: 'userId',</span><br><span class="line"> autoIncrement: false</span><br><span class="line"> });</span><br><span class="line"> const idx = store.createIndex('ageIndex', 'age', {</span><br><span class="line"> unique: false</span><br><span class="line"> })</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><p> 这样我们就创建了一条索引.</p><h2 id="创建索引-1"><a href="#创建索引-1" class="headerlink" title="创建索引"></a>创建索引</h2><p> 这在创建了一条索引之后我们就可以来使用它了.我们使用对象仓库上的index方法,通过传入一个索引名.来拿到一个索引对象.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const index = store.index('ageIndex');</span><br></pre></td></tr></table></figure><p> 然后我们就可以使用这个索引了.比如说我们要拿到年龄在20岁以上的数据,升序排列.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">const request = indexedDB.open('myDatabase', 4);</span><br><span class="line">request.addEventListener('success', e => {</span><br><span class="line"> const db = e.target.result;</span><br><span class="line"> const tx = db.transaction('Users', 'readwrite');</span><br><span class="line"> const store = tx.objectStore('Users');</span><br><span class="line"> const index = store.index('ageIndex');</span><br><span class="line"> const req = index.openCursor(IDBKeyRange.lowerBound(20), 'next');</span><br><span class="line"> req.addEventListener('success', e => {</span><br><span class="line"> const cursor = e.target.result;</span><br><span class="line"> if (cursor) {</span><br><span class="line"> console.log(cursor.value.age);</span><br><span class="line"> cursor.continue();</span><br><span class="line"> } else {</span><br><span class="line"> console.log('检索结束');</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h2 id="indexedDB-的兼容性"><a href="#indexedDB-的兼容性" class="headerlink" title="indexedDB 的兼容性"></a>indexedDB 的兼容性</h2><p>上面是我对indexedDB一些粗浅的总结,希望对大家有所帮助.如果文中有何不当之处请予以斧正,谢谢.</p><p>参考资料:</p><p>MDN—IndexedDB<br>MDN—基本概念<br>HTML5 进阶系列:indexedDB 数据库</p>]]></content>
<summary type="html">
<p><strong> 前端IndexedDB 存储方案:</strong> <excerpt in="" index="" |="" 首页摘要=""><br>IndexedDB 是一种使用浏览器存储大量数据的方法.它创造的数据可以被查询,并且可以离线使用. IndexedDB对于那些需要存储大量数据,或者是需要离线使用的程序是非常有效的解决方法. — MDN<br>
</summary>
<category term="前端" scheme="sqyun.github.io/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="js" scheme="sqyun.github.io/tags/js/"/>
</entry>
<entry>
<title>测试</title>
<link href="sqyun.github.io/2018/05/29/%E7%AC%AC%E4%B8%80%E5%A4%A9/"/>
<id>sqyun.github.io/2018/05/29/第一天/</id>
<published>2018-05-29T12:04:00.000Z</published>
<updated>2018-05-29T12:08:23.437Z</updated>
<content type="html"><![CDATA[<p><strong> 测试:</strong> <excerpt in="" index="" |="" 首页摘要=""><br>测试<br><a id="more"></a></excerpt></p><p><the rest="" of="" contents="" |="" 余下全文=""><br>测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试</the></p>]]></content>
<summary type="html">
<p><strong> 测试:</strong> <excerpt in="" index="" |="" 首页摘要=""><br>测试<br>
</summary>
<category term="test" scheme="sqyun.github.io/categories/test/"/>
<category term="test" scheme="sqyun.github.io/tags/test/"/>
</entry>
</feed>