前端儲存之sessionStorage、localStorage、cookie和indexedDB
一、js三種儲存方式區別
sessionStorage、localStorage、cookie
相同點:都儲存在瀏覽器端,同源的:
不同點:
1》傳遞方式不同
cookie資料始終在同源的http請求中攜帶(即使不需要),即cookie在瀏覽器和伺服器間來回傳遞。
sessionStorage和loaclStorage不會自動把資料發給伺服器,僅在本地儲存。
2》資料大小不同
cookie資料還有路徑(path)的概念,可以限制cookie只屬於某個路徑下。
儲存大小限制也不同,cookie資料不能超過4k,同時因為每次http請求都會攜帶cookie,所以cookie只適合儲存很小的資料,如會話標識。
sessionStorage和localStorage雖然也有儲存大小的限制,但比cookie大得多,可以達到5M或者更大。
3》資料有效期不同
sessionStorage:僅在當前瀏覽器視窗關閉前有效,自然也就不可能持久保持;
localStorage:始終有效,視窗或瀏覽器關閉也一直儲存,因此用作持久資料;
cookie只在設定cookie過期時間之前一直有效,即使視窗或瀏覽器關閉。
4》作用域不同
sessionStorage不在不同的瀏覽器視窗中共享,即使是同一個頁面;
localStorage在所有同源視窗中都是共享的;
cookie也是在所有同源視窗中都是共享的。
Web Storage支援事件通知機制,可以將資料更新的通知傳送給監聽者。
Web Storage的api介面使用更方便。
二、詳細介紹cookie用法
1.Cookie具有生命週期
Cookie可以保持登入資訊到使用者下次與伺服器的會話,換句話說,下次訪問同一網站時,使用者會發現不必輸入使用者名稱和密碼就已經登入了(當然,不排除使用者手工刪除Cookie)。而還有一些Cookie在使用者退出會話的時候就被刪除了,這樣可以有效保護個人隱私。
Cookie在生成時就會被指定一個Expire值,這就是Cookie的生存週期,在這個週期內Cookie有效,超出週期Cookie就會被清除。有些頁面將Cookie的生存週期設定為“0”或負值,這樣在關閉瀏覽器時,就馬上清除Cookie,不會記錄使用者資訊,更加安全。
雖然網站images.google.com與網站www.google.com同屬於Google,但是域名不一樣,二者同樣不能互相操作彼此的Cookie。
問題來了 舉個例子:
訪問玩zhidao.baidu.com 再訪問wenku.baidu.com還需要重新登陸百度賬號嗎?
解決辦法: 設定document.domain = ‘baidu.com’;
讓頁面屬於這個基礎域名下(那麼此頁面和任何二級域名為baidu.com的)
3.封裝自己Cookie的增刪改查函式
/*
2017/5/20
cookie操作
*/
//新增cookie
function setCookie(key, value, iDay) {
var oDate = new Date();
oDate.setDate(oDate.getDate() + iDay);
document.cookie = key + '=' + value + ';expires=' + oDate;
}
//刪除cookie
function removeCookie(key) {
setCookie(key, '', -1);//這裡只需要把Cookie保質期退回一天便可以刪除
}
//獲取cookie
function getCookie(key) {
var cookieArr = document.cookie.split('; ');
for(var i = 0; i < cookieArr.length; i++) {
var arr = cookieArr[i].split('=');
if(arr[0] === key) {
return arr[1];
}
}
return false;
}
2.Cookie滿足同源策略
三、indexedDB
在前一個階段的工作中,專案組要開發一個平臺,為了做出更好的使用者體驗,實現快速、高質量的互動,從而更快得到使用者的反饋,要求在前端把資料儲存起來,之後我去研究了下現在比較流行的前端儲存資料庫,找到了indexedDB,於是便對indexedDB做了一個較為深入的探索,此文就是記錄探索過程的一些心得體會。
indexedDB為何物
在使用一個技術之前,先搞清楚它是什麼,這對你的理解很重要,從DB就可以看出,它肯定是一個數據庫,而說到資料庫,有兩種不同型別的資料庫,就是關係型資料庫和非關係型資料庫,關係型資料庫如Mysql、Oracle等將資料儲存在表中,而非關係型資料庫如Redis、MongoDB等將資料集作為個體物件儲存。indexedDB就是一個非關係型資料庫,它不需要你去寫一些特定的sql語句來對資料庫進行操作,因為它是nosql的,資料形式使用的是json,
indexedDB出現的意義
也許熟悉前端儲存的會說,不是有了LocalStorage和Cookies嗎?為什麼還要推出indexedDB呢?其實對於在瀏覽器裡儲存資料,你可以使用cookies或local storage,但它們都是比較簡單的技術,而IndexedDB提供了類似資料庫風格的資料儲存和使用方式。
首先說說Cookies,英文直接翻譯過來就是小甜點,聽起來很好吃,實際上並不是,每次HTTP接受和傳送都會傳遞Cookies資料,它會佔用額外的流量。例如,如果你有一個10KB的Cookies資料,傳送10次請求,那麼,總計就會有100KB的資料在網路上傳輸。Cookies只能是字串。瀏覽器裡儲存Cookies的空間有限,很多使用者禁止瀏覽器使用Cookies。所以,Cookies只能用來儲存小量的非關鍵的資料。
其次說說LocalStorage,LocalStorage是用key-value鍵值模式儲存資料,但跟IndexedDB不一樣的是,它的資料並不是按物件形式儲存。它儲存的資料都是字串形式。如果你想讓LocalStorage儲存物件,你需要藉助JSON.stringify()能將物件變成字串形式,再用JSON.parse()將字串還原成物件。但如果要儲存大量的複雜的資料,這並不是一種很好的方案。畢竟,localstorage就是專門為小數量資料設計的,所以它的api設計為同步的。而IndexedDB很適合儲存大量資料,它的API是非同步呼叫的。IndexedDB使用索引儲存資料,各種資料庫操作放在事務中執行。IndexedDB甚至還支援簡單的資料型別。IndexedDB比localstorage強大得多,但它的API也相對複雜。對於簡單的資料,你應該繼續使用localstorage,但當你希望儲存大量資料時,IndexedDB會明顯的更適合,IndexedDB能提供你更為複雜的查詢資料的方式。
indexedDB的特性
1.物件倉庫
有了資料庫後我們自然希望建立一個表用來儲存資料,但indexedDB中沒有表的概念,而是objectStore,一個數據庫中可以包含多個objectStore,objectStore是一個靈活的資料結構,可以存放多種型別資料。也就是說一個objectStore相當於一張表,裡面儲存的每條資料和一個鍵相關聯。我們可以使用每條記錄中的某個指定欄位作為鍵值(keyPath),也可以使用自動生成的遞增數字作為鍵值(keyGenerator),也可以不指定。選擇鍵的型別不同,objectStore可以儲存的資料結構也有差異。
如上圖,有一個用於儲存person的object Store,這個倉庫的鍵就是person的ID值。
- 事務性
在indexedDB中,每一個對資料庫操作是在一個事務的上下文中執行的。事務範圍一次影響一個或多個object stores,你通過傳入一個object store名字的陣列到建立事務範圍的函式來定義。例如:db.transaction(storeName, ‘readwrite’),建立事務的第二個引數是事務模式。當請求一個事務時,必須決定是按照只讀還是讀寫模式請求訪問。
- 基於請求
對indexedDB資料庫的每次操作,描述為通過一個請求開啟資料庫,訪問一個object store,再繼續。IndexedDB API天生是基於請求的,這也是API非同步本性指示。對於你在資料庫執行的每次操作,你必須首先為這個操作建立一個請求。當請求完成,你可以響應由請求結果產生的事件和錯誤。
- 非同步
在IndexedDB大部分操作並不是我們常用的呼叫方法,返回結果的模式,而是請求—響應的模式,所謂非同步API是指並不是這條指令執行完畢,我們就可以使用request.result來獲取indexedDB物件了,就像使用ajax一樣,語句執行完並不代表已經獲取到了物件,所以我們一般在其回撥函式中處理。
indexedDB怎麼玩
IndexedDB 鼓勵使用的基本模式如下所示:
1.開啟資料庫並且開始一個事務。
2.建立一個 object store。
3.構建一個請求來執行一些資料庫操作,像增加或提取資料等。
4.通過監聽正確型別的 DOM 事件以等待操作完成。
5.在操作結果上進行一些操作(可以在 request 物件中找到)
接下來如果想要理解indexedDB具體怎麼玩,最好的方法就是建立一個簡單的web應用:把人的姓名、電話、地址儲存在IndexedDB裡。IndexedDB裡提供了簡單的增、刪、改、查介面,介面如下:
1.開啟資料庫
a) 首先,你需要知道你的瀏覽器是否支援IndexedDB。
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
if(!indexedDB)
{
console.log("你的瀏覽器不支援IndexedDB");
}
b) 建立請求開啟indexedDB:一旦你的瀏覽器支援IndexedDB,我們就可以開啟它。你不能直接開啟IndexedDB資料庫。IndexedDB需要你建立一個請求來開啟它。
var request = indexedDB.open(name, version);
第一個引數是資料庫的名稱,第二個引數是資料庫的版本號。版本號可以在升級資料庫時用來調整資料庫結構和資料。但你增加資料庫版本號時,會觸發onupgradeneeded事件,這時可能會出現成功、失敗和阻止事件三種情況:
request.onerror = function(e) {
console.log(e.currentTarget.error.message);
};
request.onsuccess = function(e) {
myDB.db = e.target.result;
console.log('成功開啟DB');
};
request.onupgradeneeded = function(e) {
var db = e.target.result;
if (!db.objectStoreNames.contains('person')) {
console.log("我需要建立一個新的儲存物件");
//如果表格不存在,建立一個新的表格(keyPath,主鍵 ; autoIncrement,是否自增),會返回一個物件(objectStore)
var objectStore = db.createObjectStore('person', {
keyPath: "id",
autoIncrement: true
});
//指定可以被索引的欄位,unique欄位是否唯一
objectStore.createIndex("name", "name", {
unique: false
});
objectStore.createIndex("phone", "phone", {
unique: false
});
}
console.log('資料庫版本更改為: ' + version);
};
onupgradeneeded事件在第一次開啟頁面初始化資料庫時會被呼叫,或在當有版本號變化時。所以,你應該在onupgradeneeded函式裡建立你的儲存資料。如果沒有版本號變化,而且頁面之前被開啟過,你會獲得一個onsuccess事件。
- 新增資料
a) 首先需要建立一個事務,並要求具有讀寫許可權
var transaction = db.transaction(storeName, 'readwrite');
b) 獲取objectStore,再呼叫add方法新增資料
var store = transaction.objectStore(storeName);
var request = store.get(key);
request.onsuccess = function(e) {
data = e.target.result;
console.log(student.name);
};
3.刪除資料
刪除跟新增一樣,需要建立事務,然後呼叫刪除介面,通過key刪除物件。
var transaction = db.transaction(storeName, 'readwrite');
var store = transaction.objectStore(storeName);
store.delete(key);
4.查詢資料
a) 按key查詢
開啟事務,獲取objectStore,呼叫往get()方法,往方法裡傳入物件的key值,取出相應的物件
var transaction = db.transaction(storeName, 'readwrite');
var store = transaction.objectStore(storeName);
var request = store.get(key);
request.onsuccess = function(e) {
data = e.target.result;
console.log(student.name);
};
b) 使用索引查詢
我們可以在建立object store的時候指明索引,使用object store的createIndex建立索引,方法有三個引數:索引名稱、索引屬性欄位名、索引屬性值是否唯一。
objectStore.createIndex("name", "name", {
unique: false
});
如上程式碼中,我們建好了name索引,就可以用該索引來進行查詢了:
var transaction = db.transaction(storeName);
var store = transaction.objectStore(storeName);
var index = store.index(search_index);
index.get(value).onsuccess = function(e) {
data = e.target.result;
console.log(student.id);
}
c) 遊標遍歷資料
對資料庫熟悉的同學很好理解遊標的作用,有了資料庫object store的遊標,我們就可以利用遊標遍歷object store了。
var transaction = db.transaction(storeName);
var store = transaction.objectStore(storeName);
var request = store.openCursor();//開啟遊標
var dataList = new Array();
var i = 0;
request.onsuccess = function(e) {
var cursor = e.target.result;
if (cursor) {
console.log(cursor.key);
dataList[i] = cursor.value;
console.log(dataList[i].name);
i++;
cursor.continue();
}
data = dataList;
};
4.更新物件
更新物件,首先要把它取出來,修改,然後再放回去。
var transaction = db.transaction(storeName, 'readwrite');
var store = transaction.objectStore(storeName);
var request = store.get(key);
request.onsuccess = function(e) {
var data = e.target.result;
for (a in newData) {
//除了keypath之外
data.a = newData.a;
}
store.put(data);
};
5.關閉與刪除資料庫
關閉資料庫可以直接呼叫資料庫物件的close方法
function closeDB(db) {
db.close();
}
刪除資料庫使用資料庫物件的deleteDatabase方法
function deleteDB(name) {
indexedDB.deleteDatabase(name);
}
總結
以上就是indexedDB的一些基本概念以及使用,由於篇幅原因,還有一些更深入的細節沒有介紹,比如indexedDB的遊標結合索引,發揮其真正的優勢,有興趣的小夥伴可以繼續深入研究,還有就是要注意瀏覽器的支援問題,IE9以及更早的版本並不支援,火狐和谷歌瀏覽器沒有問題,推薦使用,文章如果紕漏或者不足,歡迎指正~