indexedDB简单介绍
indexedDB
一、其它幾種前端存儲:
1、cookie
HTTP cookie 通常也叫作 cookie,最初用于在客戶端存儲會話信息。這個規范要求服務器在響應
HTTP 請求時,通過發送 Set-Cookie HTTP 頭部包含會話信息。例如, 下面是包含這個頭部的一個 HTTP
響應 :
這個 HTTP 響應會設置一個名為"name",值為"value"的 cookie。名和值在發送時都會經過 URL
編碼。瀏覽器會存儲這些會話信息,并在之后的每個請求中都會通過 HTTP 頭部 cookie 再將它們發回服
務器,比如:
這些發送回服務器的額外信息可用于唯一標識發送請求的客戶端。
cookie 是與特定域綁定的。設置 cookie 后,它會與請求一起發送到創建它的域。這個限制能保證
cookie 中存儲的信息只對被認可的接收者開放,不被其他域訪問。因為 cookie 存儲在客戶端機器上,所以為保證它不會被惡意利用,瀏覽器會施加限制。 同時, cookie也不會占用太多磁盤空間。
cookie 在瀏覽器中是由以下參數構成的(這些參數在 Set-Cookie 頭部中使用分號加空格隔開 ) :
- 名稱:唯一標識 cookie 的名稱。 cookie 名不區分大小寫,因此 myCookie 和 MyCookie 是同一
個名稱。不過,實踐中最好將 cookie 名當成區分大小寫來對待,因為一些服務器軟件可能這樣
對待它們。 cookie 名必須經過 URL 編碼。 - 值:存儲在 cookie 里的字符串值。這個值必須經過 URL 編碼。
- 域: cookie 有效的域。發送到這個域的所有請求都會包含對應的 cookie。這個值可能包含子域(如
www.wrox.com),也可以不包含(如.wrox.com 表示對 wrox.com 的所有子域都有效)。如果不明
確設置,則默認為設置 cookie 的域。 - 路徑:請求 URL 中包含這個路徑才會把 cookie 發送到服務器。例如,可以指定 cookie 只能由
http://www.wrox.com/books/訪問,因此訪問 http://www.wrox.com/下的頁面就不會發送 cookie,即
使請求的是同一個域。 - 過期時間:表示何時刪除 cookie 的時間戳(即什么時間之后就不發送到服務器了)。默認情況下,
瀏覽器會話結束后會刪除所有 cookie。不過,也可以設置刪除 cookie 的時間。這個值是 GMT 格
式( Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于指定刪除 cookie 的具體時間。這樣即使關閉
瀏覽器 cookie 也會保留在用戶機器上。把過期時間設置為過去的時間會立即刪除 cookie。 - 安全標志:設置之后,只在使用 SSL 安全連接的情況下才會把 cookie 發送到服務器。例如,請
求https://www.wrox.com 會發送 cookie,而請求 http://www.wrox.com 則不會 ;
這個頭部設置一個名為"name"的 cookie,這個 cookie 在 2007 年 1 月 22 日 7:10:24 過期,對
www.wrox.com 及其他 wrox.com 的子域(如 p2p.wrox.com)有效。
安全標志 secure 是 cookie 中唯一的非名/值對,只需一個 secure 就可以了。比如:
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; domain=.wrox.com; path=/; secure
Other-header: other-header-value
這里創建的 cookie 對所有 wrox.com 的子域及該域中的所有頁面有效(通過 path=/指定)。不過,
這個 cookie 只能在 SSL 連接上發送,因為設置了 secure 標志。
要知道,域、路徑、過期時間和 secure 標志用于告訴瀏覽器什么情況下應該在請求中包含 cookie。
這些參數并不會隨請求發送給服務器,實際發送的只有 cookie 的名/值對 ;
因為在 JavaScript 中讀寫 cookie 不是很直觀,所以可以通過輔助函數來簡化相應的操作。與 cookie
相關的基本操作有讀、寫和刪除。這些在 CookieUtil 對象中表示如下:
2、Storage
Web Storage 的定義了兩個對象: localStorage 和 sessionStorage。 localStorage 是永久存儲機制, sessionStorage 是跨會話的存儲機制。這兩種瀏覽器存儲 API 提供了在瀏覽器中不受頁面刷新影響而存儲數據的兩種方式。
Storage 類型用于保存名/值對數據,直至存儲空間上限(由瀏覽器決定)。 Storage 的實例與其他
對象一樣,但增加了以下方法 :
- clear():刪除所有值;不在 Firefox 中實現。
- getItem(name):取得給定 name 的值
- key(index):取得給定數值位置的名稱
- removeItem(name):刪除給定 name 的名/值對
- setItem(name, value):設置給定 name 的值。
sessionStorage:
因為 sessionStorage 對象是 Storage 的實例,所以可以通過使用 setItem()方法或直接給屬
性賦值給它添加數據。下面是使用這兩種方式的例子:
// 使用方法存儲數據
sessionStorage.setItem("name", "Nicholas");
// 使用屬性存儲數據
sessionStorage.book = "Professional JavaScript";
可以使用 getItem()或直接訪問屬性名來取得。下面是使用這兩種方式的例子:
// 使用方法取得數據
let name = sessionStorage.getItem("name");
// 使用屬性取得數據
let book = sessionStorage.book;
可以結合 sessionStorage 的 length 屬性和 key()方法遍歷所有的值:
for (let i = 0, len = sessionStorage.length; i < len; i++){let key = sessionStorage.key(i);let value = sessionStorage.getItem(key);alert(`${key}=`${value}`); } for (let key in sessionStorage){let value = sessionStorage.getItem(key);alert(`${key}=${value}`); }要從 sessionStorage 中刪除數據,可以使用 delete 操作符直接刪除對象屬性,也可以使用
removeItem()方法。下面是使用這兩種方式的例子:
sessionStorage 對象應該主要用于存儲只在會話期間有效的小塊數據。如果需要跨會話持久存儲
數據,可以使用 globalStorage 或 localStorage
存儲在 localStorage 中的數據會保留到通過 JavaScript 刪除或者用戶清除瀏覽器緩存。 localStorage 數據不受頁面刷新影響,也不會因關閉窗口、標簽頁或重新啟動瀏覽器而丟失。
存儲事件
每當 Storage 對象發生變化時,都會在文檔上觸發 storage 事件。使用屬性或 setItem()設置
值、使用 delete 或 removeItem()刪除值,以及每次調用 clear()時都會觸發這個事件。這個事件的
事件對象有如下 4 個屬性。
-
domain:存儲變化對應的域。
-
key:被設置或刪除的鍵。
-
newValue:鍵被設置的新值,若鍵被刪除則為 null。
-
oldValue:鍵變化之前的值。
可以使用如下代碼監聽 storage 事件:
window.addEventListener("storage",(event) => alert('Storage changed for ${event.domain}' ));對于 sessionStorage 和 localStorage 上的任何更改都會觸發 storage 事件,但 storage 事
件不會區分這兩者。
二、indexedDB簡介
IndexedDB和傳統的關系型數據不同的是,它是一個key-value型的數據庫。
value可以是復雜的結構體對象,key可以是對象的某些屬性值也可以是其他的對象(包括二進制對象)。你可以使用對象中的任何屬性做為index,以加快查找。
IndexedDB是自帶transaction的,所有的數據庫操作都會綁定到特定的事務上,并且這些事務是自動提交了,IndexedDB并不支持手動提交事務。
IndexedDB API大部分都是異步的,在使用異步方法的時候,API不會立馬返回要查詢的數據,而是返回一個callback。
異步API的本質是向數據庫發送一個操作請求,當操作完成的時候,會收到一個DOM event,通過該event,我們會知道操作是否成功,并且獲得操作的結果。
IndexedDB是一種 NoSQL 數據庫,和關系型數據庫不同的是,IndexedDB是面向對象的,它存儲的是Javascript對象。
IndexedDB還有一個很重要的特點是其同源策略,每個源都會關聯到不同的數據庫集合,不同源是不允許訪問其他源的數據庫,從而保證了IndexedDB的安全性。
三、使用原因:開發者需要在本地進行永久存儲
當我們進行一些較大的SPA頁面開發時,我們會需要進行一些數據的本地存儲。
當數據量不大時,我們可以通過SessionStorage或者LocalStorage來進行存儲,但是當數據量較大,或符合一定的規范時,我們可以使用數據庫來進行數據的存儲。
在瀏覽器提供的數據庫中,共有web sql和IndexedDB兩種。相較于HTML5已經廢棄的web sql來說,更推薦大家使用IndexedDB。
四、indexedDB的相關操作
// 假如一開始有這樣的數據需要存儲 let data = [{id: 1,name: "lzc",age: 18,sex: "man",addTime: "2021-2-1"},{id: 2,name: "cb",age: 19,sex: "man",addTime: "2021-2-2"},{id: 3,name: "kj",age: 20,sex: "woman",addTime: "2021-2-3"},{id: 4,name: "juanjuan",age: 21,sex: "woman",addTime: "2021-2-4"} ]1、創建或者打開數據庫
/* 不同的瀏覽器對于IndexedDB有不同的實現,正常來說,我們可以使用window.indexedDB來獲取到瀏覽器的indexedDB對象。但是對于某些瀏覽器來說,還沒有使用標準的window.indexedDB,而是用帶前綴的實現使用IndexedDB第一步,就是創建或打開一個數據庫。我們使用window.indexedDB.open(DBName)這個API來打進行操作。 */ window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;if (!window.indexedDB) {console.log("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available."); } else {const request = window.indexedDB.open('people');request.onupgradeneeded = function (event) {}request.onsuccess = function(event) {console.log(request === event.target) // true}request.onerror = function(event) {} }- 調用此接口時,如果當前數據庫不存在,則會創建一個新的數據庫;
- 當數據庫建立連接時,會返回一個IDBOpenDBRequest對象。
- 在連接建立成功時,會觸發onsuccess事件,其中函數參數event的target屬性就是request對象。
- 而在數據庫創建或者版本更新時,會觸發onupgradeneeded事件。
2、更新數據庫版本號
window.indexedDB.open的第二個參數即為版本號。在不指定的情況下,默認版本號為1。
const request = window.indexedDB.open('people', 2);在需要更新數據庫的schema(模式)時,需要更新版本號。此時我們指定一個高于之前版本的版本號,就會觸發onupgradeneeded事件。類似的,當此數據庫不存在時,也會觸發此事件并且將版本更新到置頂版本。
我們需要注意的是,版本號是一個Unsigned long long數字,這意味著它可以是一個非常大的整數。但是,它不能是一個小數,否則它將會被轉為最近的整數,同時有可能導致onUpgradeneeded事件不觸發(bug)。
3、存儲空間操作
我們使用createObjectStore來創建一個存儲空間。同時,使用createIndex來創建它的索引。
var request = window.indexedDB.open('people', 1);request.onupgradeneeded = function (event) {console.log(request === event.target) // truevar db = event.target.result;var objectStore = db.createObjectStore('user', {keyPath: 'id', autoIncrement: true});// 可以循環遍歷,給對象數組或者對象的每個鍵都生成索引(每個索引里面的數據項的排序按索引的升序來排列,索引沒有順序可言,就按原始順序)if (Object.prototype.toString.call(data) === "[object Array]" && data.length) {for (let i in data[0]) {objectStore.createIndex(i, i, { unique: false })}} else if (Object.prototype.toString.call(data) === "[object object]") {for (let i in data) {objectStore.createIndex(i, i, { unique: false })}} }request.onerror = function (event) {alert("Why didn't you allow my web app to use IndexedDB?!"); };注:只能在onupgradeneeded回調函數中創建存儲空間,而不能在數據庫打開后的success回調函數中創建。
通過createObjectStore能夠創建一個存儲空間。接受兩個參數:
而createIndex能夠給當前的存儲空間設置一個索引。它接受三個參數:
4、數據操作
1、事務transaction
在IndexedDB中,我們使用事務transaction來進行數據庫的操作。事務有三個模式(常量已經棄用)
- readOnly:只讀。
- readwrite:讀寫。
- versionchange:數據庫版本變化。
我們創建一個事務時,需要從上面選擇一種模式,如果不指定的話,則默認為只讀模式。
const transaction = db.transaction(['user'], 'readwrite');事務函數transaction的第一個參數為需要關聯的存儲空間,第二個可選參數為事務模式。與上面類似,事務成功時也會觸發onsuccess函數,失敗時觸發onerror函數。
2、增加數據
當存儲空間objectStore初始化完成后,我們可以把數據放入存儲空間中??梢允褂?add()或 put()寫入數據。這兩個方法都接收一個參數, 即要存儲的對象,并把對象保存到對象存儲。這兩個方法只在對象存儲中已存在同名的鍵時有區別。這 種情況下,add()會導致錯誤,而 put()會簡單地重寫該對象。
var request = window.indexedDB.open('people', 1);request.onsuccess = function (event) {var db = event.target.result;var transaction = db.transaction(['user'], 'readwrite');var objectStore = transaction.objectStore('user');for (let item of data) {objectStore.add(item);} }注:add方法中的第二個參數key值是指定存儲空間中的keyPath值,如果data中包含keyPath值或者此值為自增值,那么可以略去此參數。
// 1、createObjectStore第二個參數里加 { autoIncrement: true },這個時候key使用從1開始的自增數,遍歷出來的數據和原始要存儲的數據順序一致; // 2、objectStore.add(item, item.name); 指定了keyPath值,這時候遍歷出來的數據順序,可能和原始的不一樣,這里是按照keyPath值字母語序來排列的;這里寫不寫{ autoIncrement: true }都可以; // 3、createObjectStore第二個參數里加 { keyPath: "name" },這里不能再在objectStore.add(item)里面添加第二個參數,即使這里第二個參數添加的和createObjectStore里面的第二個參數的keyPath的一致;上面的只影響user對象存儲里面的排序,其它索引的排序只和自己的索引有關;
3、查找數據
1、通過特定值獲取數據(只能獲取單條數據)
- 這里默認只能獲取通過createObjectStore的第二參數的keyPath設置的參數的user對象存儲的數據,其它索引的無法查出;
- 或者使用index方法改變默認索引,比如let store = objectStore.index(“age”),再用store.get(18)就可以通過age來查詢了(前提是用createIndex創建了age索引的對象存儲,才能使用objectStore.index(“age”),才能查詢);
2、通過游標獲取數據(獲取多條數據)
當你需要遍歷整個存儲空間中的數據時,你就需要使用到游標,與傳統數據庫查詢不同,游標不會事先收集所有結果。相反,游標指向 第一個結果,并在接到指令前不會主動查找下一條數據
var request = window.indexedDB.open('people', 1);request.onsuccess = function (event) {var db = event.target.result;var transaction = db.transaction(['user'], 'readwrite');var objectStore = transaction.objectStore('user');var request = objectStore.openCursor();request.onsuccess = function (event) {var cursor = event.target.result;if (cursor) {console.log(cursor.key, cursor.value);cursor.continue();}};request.onerror = function (event) {// 錯誤處理!}; }使用游標時有一個需要注意的地方,當游標遍歷整個存儲空間但是并未找到給定條件的值時,仍然會觸發onsuccess函數。
openCursor和openKeyCursor有兩個參數:**openKeyCursor**遍歷出來的值里面沒有value對象值,其它和openCursor一致
- next,從前往后獲取所有數據(重復值也會遍歷出來)
- prev,從后往前獲取所有數據(重復值也會遍歷出來)
- nextunique,從前往后獲取數據(重復數據只取第一條,索引重復即認為重復,下同)
- prevunique,從后往前獲取數據(重復數據只取第一條)
4、使用索引
在前面構建數據庫時,我們創建了所有的索引。現在我們也可以通過索引來進行數據檢索。他的本質還是通過之前獲取數據的API來進行,只是將原來使用的keyPath屬性轉換成為了索引指定的屬性。
var request = window.indexedDB.open('test', 1);request.onsuccess = function (event) {var db = event.target.result;var transaction = db.transaction(['user'], 'readwrite');var objectStore = transaction.objectStore('user');// 使用索引var index = objectStore.index('name');// 第一種,get方法index.get('a').onsuccess = function (event) {console.log(event.target.result);}// 第二種,普通游標方法index.openCursor().onsuccess = function (event) {console.log('openCursor:', event.target.result.value);}// 第三種,鍵游標方法,該方法與第二種的差別為:普通游標帶有value值表示獲取的數據,而鍵游標沒有index.openKeyCursor().onsuccess = function (event) {console.log('openKeyCursor:', event.target.result.key);} }5、修改數據===>修改時,須帶上這條數據的索引鍵
注:put方法不僅能夠修改現有數據,也能夠往存儲空間中增加新的數據。
使用objectStore.put方法時,參數為已存在的鍵,即為修改,為不存在的鍵時,即為增加;
這里不能像查詢一樣,通過store.index()來修改索引,index上只有get方法
var transaction = db.transaction(['user'], 'readwrite'); var store = transaction.objectStore("user");// 用put增加一條新數據 var request1 = store.put({id: 5,name: "李志聰",age: 22,sex: "man",addTime: "2021-2-5" });// 用put增加一條新數據,改sex描述===>是修改時,須帶上這條數據的索引鍵 var request2 = store.put({id: 2,name: "lzc",age: 18,sex: "男",addTime: "2021-2-2" });request1.onsuccess = function (event) {}6、刪除數據
var transaction = db.transaction(['user'], 'readwrite'); var store = transaction.objectStore("user");var request = store.delete(對應某一條keyPath值);request.onsuccess = function (event) {}7、關閉數據庫
// 比如在destoryed鉤子里面可以關閉數據庫 db.close();五、安全相關
IndexedDB也受到瀏覽器同源策略的限制。
六、dexie.js庫的使用
dexie.js:A Minimalistic Wrapper for IndexedDB
基于indexDB的Dexie數據庫
// 下面配一個簡單的演示// 創建一個數據庫 若數據庫已存在則為打開 // 打開數據庫時,會判斷當前version值是否大于已經存在的version值,若大于則會upgrade即升到最高版本 var db = new Dexie("mydb");// 設定版本,添加一個person表,里面有自增的id主鍵,有name和age兩個索引 // 注意:不要像在SQL中那樣聲明所有列。只聲明要索引的屬性,即要在where(…)查詢中使用的屬性。 db.version(1).stores({person: "++id, name, age" })// 增加(還是使用上面的數據進行存儲) for(let item of data) {db.person.add(item) }// 修改 setTimeout(() => {db.person.put({id: 2,name: "聰波",age: 18,sex: "boy",addTime: "2021-2-2"})console.log(db.person.get(2)) // 一個promise對象// 普通查詢db.person.get(2).then(res => {console.log("查詢的結果為===>", res)}) }, 1000)// 帶條件查詢 setTimeout(() => {// adove、aboveOrEqual、below、belowOrEqual、between、equalsdb.person.where("age").aboveOrEqual(18).toArray().then(res => {console.log("年齡大于等于18歲的有===>", res)}) }, 2000)// 刪除 setTimeout(() => {// 刪除第一條db.person.delete(1);db.person.get(1).then(res => {console.log("第一條數據===>", res)}) }, 3000)setTimeout(() => {db.close();console.log("要是數據庫沒有關閉,下面將打印第三天數據");db.person.get(3).then(res => {console.log("第三條數據===>", res)}) }, 4000)總結
以上是生活随笔為你收集整理的indexedDB简单介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器人运动估计系列(二)——运动学方程(
- 下一篇: python3注释_python3的注释