本地存儲

各類存儲方式差別與侷限性

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)方法

相關文章
相關標籤/搜索