IndexedDB是用于客戶端的大量的結構化數據存儲和使用索引高效率搜索數據的API,它是基于W3C擬定的草案索引數據庫的API。相對DOM存儲的小存儲數據量,IndexedDB具有大容量的數據存儲功能,它分別為同步數據和異步數據提供的API,但目前只有異步數據的API在Gecko2.0?上實現。
?
一、?概述
1.?IndexedDB存儲為鍵值對:它可以存儲一些復雜的對象,而鍵可以存儲這些對像的屬性值,并且可以使用索引對對象的屬性的快速檢索。
2.?IndexedDB建立在交互數據庫模型的基礎上:任何對IndexedDB的操作都發生一個交互操作(transaction),如它提供的索引、表、游標等均與一個transaction關聯,它定義了交互的生存時間與結束時拋出的事件,這樣能很好的處理web程序在不同的tab窗口中實例的互操作。
3.?IndexedDB的API大多是異步的:你可以向數據庫發出操作的“請求”,當操作完成時會產生一個DOM事件,通過事件的類型會知道操作是否成功。
4.?IndexedDB使用“請求”機制:操作對象會接收到DOM的success和failure事件,它也有相應的onsuccess和onerror的屬性;對象還有readyState、result和errorCode屬性來查看當前“請求”的狀態,而result屬性則根據不同的“請求”返回不同的結果。
5.?IndexedDB?使用DOM事件機制來處理“請求”的結果:DOM事件的type屬性提示操作是否成功,target屬性指向發生“請求”的對象(大多數情況下是IDBRequest對象)。
6.?IndexedDB工作基本模式:
0?創建一個交互操作對象
1?發送操作“請求”
2?通過監聽DOM事件等待操作完成
3?處理“請求”結果
二、?打開數據庫
IndexedDB的操作對象是以moz開頭,如我們打開一個數據庫如下:
?
| 1 | var?request = mozIndexedDB.open("MyTestDatabase"); |
?
mozIndexedDB對象只有一個open方法,它的參數即為數據庫的名稱,它返回一個IDBRequest對象。接下來要做的就是為request添加onsuccess和onerror事件的處理,它們分別在返回的DOM事件的type為success和error時調用,
?
| 01 | request.onerror =?function(event) { |
| 03 | ??// Do something with request.errorCode! |
| 07 | request.onsuccess =?function(event) { |
| 09 | ??// Do something with request.result! |
IndexedDB采用最小化的錯誤事件處理,你不會看到很多類型的錯誤,它只提供一個錯誤的事件,可以通過event.target.errorCode來查看錯誤的信息,通常大多的錯誤都是用戶不允許web操作本地的數據庫,遠程web所擁有的權限問題。
三、?設置數據庫的version
當創建數據庫之后,需要添加數據,IndexedDB采用對象存儲。首先要檢查數據庫的版本,若不是所期望的值,就要調用setVerion()方法來設置它的版本,如:
?
| 01 | if?(db.version !=?"1.0") { |
| 03 | ??var?request = db.setVersion("1.0"); |
| 05 | ??request.onerror =?function(event) { |
| 11 | ??request.onsuccess =?function(event) { |
| 13 | ????// Set up the database structure here! |
?
IndexedDB存儲的每一個對象均與一個key?關聯,關于key?的獲取方法參見()。同時我們還可以為對你的存儲創建一個Index來查看存儲對象部分屬性值,如存儲人的信息的數據庫,我們希望保證不同的人擁有不同的email,就可以使用index和unique?flag來設置,如:
?
| 01 | // This is what our customer data looks like. |
| 05 | ??{ ssn:?"444-44-4444", name:?"Bill", age: 35, email:?"bill@company.com"?}, |
| 07 | ??{ ssn:?"555-55-5555", name:?"Donna", age: 32, email:?"donna@home.org"?} |
| 11 | var?request = db.setVersion("1.0"); |
| 13 | request.onerror =?function(event) { |
| 19 | request.onsuccess =?function(event) { |
| 21 | ??// Create an objectStore to hold information about our customers. We're |
| 23 | ??// going to use "ssn" as our key path because it's guaranteed to be |
| 27 | ??var?objectStore = db.createObjectStore("customers", { keyPath:?"ssn"?}); |
| 29 | ??// Create an index to search customers by name. We may have duplicates |
| 31 | ??// so we can't use a unique index. |
| 33 | ??objectStore.createIndex("name",?"name", { unique:?false?}); |
| 35 | ??// Create an index to search customers by email. We want to ensure that |
| 37 | ??// no two customers have the same email, so use a unique index. |
| 39 | ??objectStore.createIndex("email",?"email", { unique:?true?}); |
| 41 | ??// Store values in the newly created objectStore. |
| 43 | ??for?(i?in?customerData) { |
| 45 | ????objectStore.add(customerData[i]); |
??creatObjectStore()方法和createIndex()方法都有一個可選的對象選項來區分是創建數據庫還是索引。creatObjectStore()方法會請求“customers”創建存儲對象,并以ssn屬性為存儲對象的鍵值,任何試圖存儲進數據庫的對象都需要有ssn屬性;我們也可以通name的這個Index來查看存儲對象,但對于沒有name屬性的對象將不會顯示出來。
向數據庫中添加數據
四、?在添加數據之前,需要先創建一個transaction,創建的方法有三個參數,后兩個為可選的,第一個為要關聯的數據庫名稱數組,第二個為打開此數據庫的方式(如只讀),若無則打開的方式為只讀,如:
var?transaction?=?db.transaction(["customers"],IDBTransaction.READ_WRITE);
一個transaction生存時間是與DOM?事件相關聯的,如果創建它之后并在返回的事件中沒有使用它,就會消亡,唯一讓它處理激活狀態的就去是使用“請求”機制,當一個請求完成后,在它的回調函數中繼續請求,否則transaction就是會消亡。一個transaction有三個事件,為onerror、onsuccess和onabort,一個簡單的例子:
?
| 01 | // Do something when all the data is added to the database. |
| 03 | transaction.oncomplete =?function(event) { |
| 09 | transaction.onerror =?function(event) { |
| 11 | ??// Don't forget to handle errors! |
| 15 | var?objectStore = transaction.objectStore("customers"); |
| 17 | for?(var?i?in?customerData) { |
| 19 | ??var?request = objectStore.add(customerData[i]); |
| 21 | ??request.onsuccess =?function(event) { |
| 23 | ????// event.target.result == customerData[i].ssn |
?
五、?從數據庫中刪除數據
刪除數據很簡單,如下:
?
| 01 | var?request = db.transaction(["customers"], IDBTransaction.READ_WRITE) |
| 03 | ????????????????.objectStore("customers") |
| 05 | ????????????????.delete("444-44-4444"); |
| 07 | request.onsuccess =?function(event) { |
?
六、?數據庫中取數據
使用get()方法,參數為存儲對象的key,如:
?
| 1 | db.transaction("customers").objectStore("customers").get("444-44-4444").onsuccess =?function(event) { |
| 3 | ??alert("Name for SSN 444-44-4444 is "?+ event.target.result.name); |
?
七、?使用游標
使用get()方法需要知道存儲對象的key值,但若不知道key值,要看存儲對象,就可以使用游標,如下:
?
| 01 | var?objectStore = db.transaction("customers").objectStore("customers"); |
| 03 | objectStore.openCursor().onsuccess =?function(event) { |
| 05 | ??var?cursor = event.target.result; |
| 09 | ????alert("Name for SSN "?+ cursor.key +?" is "?+ cursor.value.name); |
| 17 | ????alert("No more entries!"); |
?
openCursor()方法有許多參數,首先你可設置遍歷的Key的范圍,其次可以設置游標遍歷的方向。Continue();表示繼續遍歷。
八、?使用索引
在數據庫中,所有的數據都是以SSN以key值來存儲的,若要通過name等其他屬性查看存儲對象,需要遍歷每個SSN并將它的name提取出判斷是否為要查看的對象,但可以通過index而更為簡單的實現,如:
?
| 1 | var?index = objectStore.index("name"); |
| 3 | index.get("Donna").onsuccess =?function(event) { |
| 5 | ??alert("Donna's SSN is "?+ event.target.result.ssn); |
?
我們還可以通過index使用cursor來遍歷存儲的數據,并根據不同的cursor打開方式,返回不同的遍歷結果,如下兩種方式:
?
| 01 | index.openCursor().onsuccess =?function(event) { |
| 03 | ??var?cursor = event.target.result; |
| 07 | ????// cursor.key is a name, like "Bill", and cursor.value is the whole object. |
| 09 | ????alert("Name: "?+ cursor.key +?", SSN: "?+ cursor.value.ssn +?", email: "+ cursor.value.email); |
| 17 | index.openKeyCursor().onsuccess =?function(event) { |
| 19 | ??var?cursor = event.target.result; |
| 23 | ????// cursor.key is a name, like "Bill", and cursor.value is the SSN. |
| 25 | ????// No way to directly get the rest of the stored object. |
| 27 | ????alert("Name: "?+ cursor.key +?", "SSN: " + cursor.value); |
?
九、?關于游標遍歷的范圍和方向
如果想要限制游標的遍歷范圍,可以使用“key?range”的對象,并將它做為openCursor()和openKeyCursor()的第一個參數,這樣的范圍可以是單個鍵值、或是一個最低邊界和最高邊界的范圍,并規定是否包括范圍,如下:
?
| 03 | var?singleKeyRange = IDBKeyRange.only("Donna"); |
| 05 | // Match anything past "Bill", including "Bill" |
| 07 | var?lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill"); |
| 09 | // Match anything past "Bill", but don't include "Bill" |
| 11 | var?lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill",?true); |
| 13 | // Match anything up to, but not including, "Donna" |
| 15 | var?upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna",?true); |
| 17 | //Match anything between "Bill" and "Donna", but not including "Donna" |
| 19 | var?boundKeyRange = IDBKeyRange.bound("Bill",?"Donna",?false,?true); |
| 21 | index.openCursor(boundKeyRange).onsuccess =?function(event) { |
| 23 | ??var?cursor = event.target.result; |
| 27 | ????// Do something with the matches. |
另外,還可以規定游標遍歷的方向,默認的是上升的方向,若使用相反的方向,可以將PREV作為openCursor()或是openKeyCursor()的第二個參數,如下:
?
| 01 | objectStore.openCursor(null, IDBCursor.PREV).onsuccess =?function(event) { |
| 03 | ??var?cursor = event.target.result; |
| 07 | ????// Do something with the entries. |
?
需要注意的是,在索引中使用游標時,由于可能有多個鍵值是相同的,這時候總是返回最低邊界的那一個對象,為解決此問題,將NEXT_NO_DUPLICATE?或是PREV_NO_DUPLICATE做為它的第二個參數,如下:
?
| 1 | index.openKeyCursor(null, IDBCursor.NEXT_NO_DUPLICATE).onsuccess =function(event) { |
| 2 | ??var?cursor = event.target.result; |
| 4 | ????// Do something with the entries. |
???
?
十、?數據庫版本的變化
當web?app需要請求數據庫的變化時,要考慮用戶在一個tab中打開老版本的app,而在另一個tab窗口中打開新版本的app時會發生什么情況,當你調用setVersion()時,所有其它打的數據庫必須顯示的接受該請求時,你才能對數據庫進行更改。
?
| 01 | mozIndexedDB.open("MyTestDatabase").onsuccess =?function(event) { |
| 03 | ??var?db = event.target.result; |
| 05 | ??// If the database is at the correct version then we can skip straight to using it. |
| 07 | ??if?(db.version ==?"1.0") { |
| 15 | ??// Check that the database isn't a newer version already. |
| 17 | ??if?(db.version !=?"") { |
| 19 | ????alert("Database has a version which we don't know how to upgrade!"); |
| 25 | ??// Otherwise we need to change the version. |
| 27 | ??var?request = db.setVersion("1.0"); |
| 29 | ??request.onblocked =?function(event) { |
| 31 | ????// If some other tab is loaded with the database, then it needs to be closed |
| 33 | ????// before we can proceed. |
| 35 | ????alert("Please close all other tabs with this site open!"); |
| 39 | ??request.onsuccess =?function(event) { |
| 41 | ????// All other databases have been closed. Set everything up. |
| 43 | ????db.createObjectStore(/* ... */); |
| 51 | function?useDatabase(db) { |
| 53 | ??// Make sure to add a handler to be notified if another page requests a version |
| 55 | ??// change. We must close the database. This allows the other page to upgrade the database. |
| 57 | ??// If you don't do this then the upgrade won't happen until the user close the tab. |
| 59 | ??db.onversionchange =?function(event) { |
| 63 | ????alert("A new version of this page is ready. Please reload!"); |
| 67 | ??// Do stuff with the database. |
?
十一、?使用javascript?Generators
注意:這只能在firefox中使用,不支持IE、chrome、Safari
Generators?在firefox中用于簡化異步代碼,但只能在javascript?1.7及后續的版本上,如:
<script?type="text/javascript;version=1.7"?src="myScript.js"></script>
myScript.js的內容如下:
?
| 01 | // Need to stash the generator in a global variable. |
| 05 | // Simple event listener function to pass the received event to the generator. |
| 07 | function?grabEvent(event) { |
| 09 | ??generator.send(event); |
| 13 | // When we're all done we can close the generator, but that must happen outside |
| 15 | // of the generator so we use a timeout. |
| 17 | function?closeGenerator() { |
| 19 | ??setTimeout(function() { |
| 29 | function?databaseOperation() { |
| 31 | ??mozIndexedDB.open("MyTestDatabase").onsuccess = grabEvent; |
| 35 | ??var?db = event.target.result; |
| 37 | ??if?(db.version !=?"1.0") { |
| 39 | ????db.setVersion("1.0").onsuccess = grabEvent; |
| 43 | ????var?transaction = event.transaction; |
| 45 | ????db.createObjectStore("stuff"); |
| 47 | ????transaction.oncomplete = grabEvent; |
| 53 | ??db.transaction(["stuff"]).objectStore("stuff").get("foo").onsuccess = grabEvent; |
| 57 | ??alert("Got result: "?+ event.target.result); |
| 63 | ??// Always have an extra yield at the end or you will see StopIteration |
| 71 | generator = databaseOperation(); |
?
十二、?安全性
需要注意的是IndexedDB在以iframe等方式加載到其它網站/網頁是是不可運用的。
?
IDBRequest
它反應了向數據庫IDBDatabase發出的請求的狀況
屬性:onsuccess?---?類型為函數,請求成功后執行,參數為請求成功產生的event(IDBSuccessEvent,?IDBTransactionEvent)
??????Onerror?---?類型為函數,請求出錯時執行,參數為錯誤時的event(IDBErrorEvent)
??????readyState?---?請求的狀態,“1”為正在執行,“2”為執行完成
示例:
?
| 3 | var?request = mozIndexedDB.open("MyTestDatabase") ; |
| 5 | request.onerror =?function(event)? {??//handle error?? }; |
| 7 | request.onsuccess=function(event) {?var?db = request.result;?//得到數據庫對象,或db=event.target.result;? }; |
IDBSuccessEvent向IndexedDB請求成功后產生的DOM事件屬性:使用event.target.result來得到請求成功后返回的結果,參見IDBRequest中示例!
轉載于:https://www.cnblogs.com/tingzi/archive/2012/08/07/2626663.html
總結
以上是生活随笔為你收集整理的About IndexDB(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。