聊一聊常見的瀏覽器端資料儲存方案

Srtian發表於2018-05-03

前言:

五一假期在擼程式碼的時候用到cookie,感覺對瀏覽器的資料儲存方案不是很瞭解,因此又去翻了兩本大頭書中間的關於瀏覽器端資料儲存的章節,同時去MDN逛了逛,又看了幾篇文章,算是對瀏覽器的資料儲存方案有了一個瞭解,在此總結一下!

瀏覽器儲存

在瀏覽器端儲存資料對我們是很有用,這相當於賦予瀏覽器記憶的功能,可以紀錄使用者的所有狀態資訊,增強使用者體驗。比如當紀錄使用者的登陸狀態時,可以讓使用者能夠更快的進行訪問,而不是每次登陸時都需要去進行繁瑣的操作。

總的來說,現在市面上最常見的資料儲存方案是以下三種:

  • Cookie
  • web儲存 (locaStorage和seesionStorage)
  • IndexedDB

圖片.png

Cookie

Cookie的又稱是HTTP Cookie,最初是在客戶端用於儲存會話資訊,從底層來看,它作為HTTP協議的一種擴充套件實現,Cookie資料會自動在web瀏覽器和web伺服器之間傳輸,因此在伺服器端指令碼就可以讀寫儲存的cookie的值,因此Cookie通常用於儲存一些通用的資料,比如使用者的登陸狀態,首選項等。雖然隨著時代的進步,HTML5所提供的web儲存機制已經逐步替代了Cookie,但有些較為老的瀏覽器還是不相容web儲存機制,因此正處於這個老舊更替階段的我們對於它還是要了解了解的。(比如我這個瓜皮還在用它,2333)

Cookie的優點

首先由於操作Cookie的API很早就已經定義和實現了,因此相比於其他的資料儲存方式,Cookie的相容性非常的好,相容現在市面上所有的主流瀏覽器,我們在使用它的時候完全不用擔心相容問題。

Cookie的缺點

說到Cookie的缺點,那就有點多了,不然也不會在Cookie後面出現web儲存等新的資料儲存的方案了。 總結起來Cookie的缺點主要是以下幾點:

  1. 儲存量小。雖不同瀏覽器的儲存量不同,但基本上都是在4kb左右。
  2. 影響效能。由於Cookie會由瀏覽器作為請求頭髮送,因此當Cookie儲存資訊過多時,會影響特定域的資源獲取的效率,增加文件傳輸的負載。
  3. 只能儲存字串。
  4. 安全問題。儲存在Cookie的任何資料可以被他人訪問,因此不能在Cookie中儲存重要的資訊。
  5. 由於第三方Cookie的濫用,所以很多老司機在瀏覽網頁時會禁用Cookie,所以我們不得不測試使用者是否支援Cookie,這也是很麻煩的一件事。

Cookie的操作

基本的Cookie操作主要有三個:讀取,寫入和刪除。但在JavaScript中去處理cookie是一件很繁瑣的事情,因為cookie中的所有的名字和值都是經過URI編碼的,所以當我們必須使用decodeURICompoent來進行解碼才能得到cookie的值。我們來看看CookieUtil物件是如何操縱cookie的:

var CookieUtil = {
	// get可根據cookie的名字獲取相應的值
	get: function() {
		const cookieName = encodeURIcOMPONET(name) + "=",
			   cookieStart = document.cookie.indexOf(cookieName),
			   cookieValue = null
		if(cookieStart > -1) {
			const cookieEnd = document.cookie.indexOf(";", cookieStart)
			if(cookieEnd == -1) {
				cookieEnd = document.cookie.length
			}
			cookieValue = decodeURICompoent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd))	
		}
		return cookieValue
	}
	// set設定一個cookie
	set: function(name, value, expires, path, domain, secure) {
		var cookieText = encodeURIComponet(name)+"="+encodeURIComponet(value)
		if(expires instanceof Date) {
			cookieText += "; expires=" + expires.toGMTString()
		}
		if(path) {
			cookieText += ";path=" + path
		}
		if(domain) {
			cookieText += "; domain" + domain
		}
		if(secure) {
			cookieText += "; secure"
		}
		document.cookie = cookieText
	}
	// 刪除已有的cookie
	unset: function(name, path, domain, secure) {
		this.set(name, "", new Date(0), path, domain, secure)
	}
}
複製程式碼

是不是很麻煩,無論是獲取一個cookie的值或是設定一個cookie都是很麻煩的事情,這也成為了後續的瀏覽器資料儲存方案出現的一大原因。

web儲存

web儲存機制最初作為HTML5的一部分被定義成API的形式,但又由於其本身的獨特性與其他的一些原因而剝離了出來,成為獨立的一個標準。web儲存標準的API包括locaStorage物件和seesionStorage物件。它所產生的主要原因主要出於以下兩個原因:

  • 人們希望有一種在cookie之外儲存回話資料的途徑。
  • 人們希望有一種儲存大量可以跨會話存在的資料的機制。

(注:其實在最初的web儲存規範中包含了兩種物件的定義:seesionStorage和globalStorage,這兩個物件在支援這兩個物件的瀏覽器中都是以windows物件屬性的形式存在的)

locaStorage

locaStorage物件在修訂過的HTML5規範中作為持久儲存客戶端資料的方案取代了我們上面所提到的globalStorage。從功能上來講,我們可以通過locaStorage在瀏覽器端儲存鍵值對資料,它相比於cookie而言,提供了更為直觀的API,且在安全上相對好一點 ,而且雖然locaStorage只能儲存字串,但它也可以儲存字串化的JSON資料,因此相比於cookie,locaStorage能儲存更復雜的資料。總的來說相較於cookie,locaStorage有以下優勢:

  • 提供了簡單明瞭的API來進行操作
  • 更加安全
  • 可儲存的資料量更大

也正是出於以上這些原因,locaStorage被視為替代cookie的解決方案,但還是要注意不要在locaStorage中儲存敏感資訊。

locaStorage的基本語法

locaStorage的基本操作很簡單,示例如下:

// 使用方法儲存資料
locaStorage.setItem("name", "Srtian")
// 使用屬性儲存資料
locaStorage.say = "Hello world"
// 使用方法讀取資料
const name = locaStorage.getItem("name")
// 使用屬性讀取資料
const say = locaStorage.say
// 刪除資料
locaStorage.removeItem("name")
複製程式碼

但需要注意的是,我們上面的示例全是儲存字串格式的資料,當我們需要傳輸其他格式的資料時,我們就需要將這些資料全部轉換為字串格式,然後再進行儲存:

const user = {name:"Srtian", age: 22}
localStorage.setItem("user", JSON.stringify(user))
複製程式碼

當然,我們在獲取值的時候也別忘了將其轉化回來:

var age = JSON.parse(locaStorage.user)
複製程式碼

locaStorage儲存資料的有效期與作用域

通過locaStorage儲存的資料時永久性的,除非我們使用removeItem來刪除或者使用者通過設定瀏覽器配置來刪除,負責資料會一直保留在使用者的電腦上,永不過期。

locaStorage的作用域限定在文件源級別的(意思就是同源的才能共享),同源的文件間會共享locaStorage的資料,他們可以互相讀取對方的資料,甚至有時會覆蓋對方的資料。當然,locaStorage的作用域同樣也受瀏覽器的限制。

locaStorage的相容

locaStorage的相容如下表所示:

    Feature 	Chrome 	Edge 	Firefox (Gecko) Internet Explorer 	Opera 	Safari (WebKit)
localStorage 	4 	(Yes) 	   3.5 	            8 	             10.50     4
sessionStorage 	5 	(Yes) 	   2 	            8 	             10.50 	   4
複製程式碼

sessionStorage

sessionStorage是web儲存機制的另一大物件,sessionStorage 屬性允許我們去訪問一個 session Storage 物件。它與 localStorage 相似,不同之處在於 localStorage裡面儲存的資料沒有過期時間設定,而Session Storage只儲存當前會話頁的資料,且只有當使用者關閉當前會話頁或瀏覽器時,資料才會被清除。

sessionStorage的基本語法

我們可以通過下面的語法,來儲存,獲取,刪除資料,大體語法與:

// 儲存資料到sessionStorage
sessionStorage.setItem('name', 'Srtian');

// 從sessionStorage獲取資料
var data = sessionStorage.getItem('name');

// 從sessionStorage刪除儲存的資料
sessionStorage.removeItem('name');

// 從sessionStorage刪除所有儲存的資料
sessionStorage.clear();
複製程式碼

下面的示例會自動儲存一個文字輸入框的內容,如果瀏覽器因偶然因素被重新整理了,文字輸入框裡面的內容會被恢復,寫入的內容不會丟失:

// 獲取文字輸入框
var field = document.getElementById("field")

// 檢測是否存在 autosave 鍵值
// (這個會在頁面偶然被重新整理的情況下存在)
if (sessionStorage.getItem("autosave")) {
  // 恢復文字輸入框的內容
  field.value = sessionStorage.getItem("autosave")
}
// 監聽文字輸入框的 change 事件
field.addEventListener("change", function() {
  // 儲存結果到 sessionStorage 物件中
  sessionStorage.setItem("autosave", field.value)
})
複製程式碼

在相容性和優點方面,sessionStorage和locaStorage是差不多的,因此在此也就不多說了,下面我們來聊一聊IndexedDB。

IndexedDB

雖然web儲存機制對於儲存較少量的資料非常便捷好用,但對於儲存更大量的結構化資料來說,這種方法就不太滿足開發者們的需求了。IndexedDB就是為了應對這個需求而產生的,它是由HTML5所提供的一種本地儲存,用於在瀏覽器中儲存較大資料結構的 Web API,並提供索引功能以實現高效能查詢。它一般用於儲存大量使用者資料並要求資料之間有搜尋需要的場景,當網路斷開時,使用者就可以做一些離線的操作。它較之SQL更為方便,不需要寫一些特定的語法對資料進行操作,資料格式是JSON。

IndexedDB的基本語法

使用IndexedDB在瀏覽器端儲存資料會比上述的其他方法更為複雜。首先,我們需要建立資料庫,並指定這個資料庫的版本號:

// 注意資料庫的版本號只能是整數
const request = IndexedDB.open(databasename, version)
複製程式碼

然後我們需要生成處理函式,需要注意的是onupgradeneeded 是我們唯一可以修改資料庫結構的地方。在這裡面,我們可以建立和刪除物件儲存空間以及構建和刪除索引。 :

request.onerror = function() {
	// 建立資料庫失敗時的回撥函式
}
request.onsuccess = function() {
	// 建立資料庫成功時的回撥函式
}
request.onupgradeneededd = function(e) {
	 // 當資料庫改變時的回撥函式
}

複製程式碼

然後我們就可以建立物件儲存空間了,物件儲存空間僅呼叫createObjectStore()就可以建立。這個方法使用儲存空間的名稱,和一個物件引數。即便這個引數物件是可選的,它還是非常重要的,因為它可以讓我們定義重要的可選屬性和完善你希望建立的物件儲存空間的型別。

request.onupgradeneeded = function(event) {
	const db = event.target.result
	const objectStore = db.createObjectStore('name', { keyPath:'id' })
}
複製程式碼

物件的儲存空間我們已經建立好了,接下來我們就可以進行一系列的騷操作了,比如來個蛇皮走位!不不不,口誤口誤,比如新增資料:

addData: function(db, storename, data) {
	const store = store = db.transaction(storename, 'readwrite').objectStore(storename)
	for(let i = 0; i < data.length; i++) {
		const request = store.add(data[i])
		request.onerror = function() {
			console.error('新增資料失敗')
		}
		request.onsuccess = function() {
			console.log('新增資料成功')
		}
	}
}
複製程式碼

如果我們想要修改資料,語法與新增資料差不多,因為重複新增已存在的資料會更新原本的資料,但還是有細小的差別:

putData: function(db, storename, data) {
	const store = store = db.transaction(storename, 'readwrite').objectStore(storename)
	for(let i = 0; i < data.length; i++) {
		const request = store.put(data[i])
		request.onerror = function() {
			console.error('修改資料失敗')
		}
		request.onsuccess = function() {
			console.log('修改資料成功')
		}
	}
}
複製程式碼

獲取資料:

getDataByKey: function(db, storename, key) {
	const store = store = db.transaction(storename, 'readwrite').objectStore(storename)
	const request = store.get(key)
	request.onerror = function() {
		console.error('獲取資料失敗')
	}
	request.onsuccess = function(e) {
		const result = e.target.result
		console.log(result)
	}
}
複製程式碼

刪除資料:

deleteDate: function(db, storename, key) {
	const store = store = db.transaction(storename, 'readwrite').objectStore(storename)
	store.delete(key)
	console.log('已刪除儲存空間' + storename + '中的' + key + '紀錄')
}
複製程式碼

關閉資料庫:

db.close
複製程式碼

IndexedDB的優點(相較於前面的儲存方案)

  • 擁有更大的儲存空間
  • 能夠處理更為複雜和結構化的資料
  • 擁有更多的互動控制
  • 每個'database'中可以擁有多個'database'和'table'

IndexedDB的侷限性

瞭解了IndexedDB的優點,我們當然也要來聊一聊IndexedDB的侷限性與適用的場景:

1. 儲存空間限制

一個單獨的資料庫專案的大小沒有限制。然而可能會限制每個 IndexedDB 資料庫的大小。這個限制(以及使用者介面對它進行斷言的方式)在各個瀏覽器上也可能有所不同:

  • Firefox: 對 IndexedDB 資料庫的大小沒有限制。在使用者介面上只會針對儲存超過 50 MB 大小的 BLOB(二進位制大物件)請求許可權。這個大小的限額可以通過 dom.indexedDB.warningQuota 首選項進行自定義。(定義在 http://mxr.mozilla.org/mozilla-central/source/modules/libpref/src/init/all.js)。
  • Google Chrome:https://developers.google.com/chrome...rage#temporary

2. 相容性問題

圖片.png
從上面的圖我們可以看出對於IndexedDB的相容來講比前面所提及的儲存方案要差不少,因此在使用IndexedDB時,我們也要好好的考慮相容性的問題

3. indexedDB受同源策略的限制

indexedDB使用同源原則,這意味著它把儲存空間繫結到了建立它的站點的源(典型情況下,就是站點的域或是子域),所以它不能被任何其他源訪問。要著重指出的一點是 IndexedDB 不適用於從另一個站點載入進框架的內容 (不管是 還是 。這是一項安全措施。詳情請看這個:https://bugzilla.mozilla.org/show_bug.cgi?id=595307

除此之外,IndexedDB還存在諸如:不適合儲存敏感資料,相較於web儲存機制的操作更加複雜等問題,這都是我們在使用IndexedDB時需要考慮的。

相關文章