前言
隨著移動(dòng)網(wǎng)絡(luò)的發(fā)展與演化辨赐,我們手機(jī)上現(xiàn)在除了有原生 App,還能跑“WebApp”——它即開(kāi)即用奈惑,用完即走。一個(gè)優(yōu)秀的 WebApp 甚至可以擁有和原生 App 媲美的功能和體驗(yàn)雷激。WebApp 優(yōu)異的性能表現(xiàn),有一部分原因要?dú)w功于瀏覽器存儲(chǔ)技術(shù)的提升告私。cookie存儲(chǔ)數(shù)據(jù)的功能已經(jīng)很難滿(mǎn)足開(kāi)發(fā)所需屎暇,逐漸被Web Storage、IndexedDB所取代驻粟,本文將介紹這幾種存儲(chǔ)方式的差異和優(yōu)缺點(diǎn)根悼。
一、cookie
1.cookie的來(lái)源
cookie 的本職工作并非本地存儲(chǔ)格嗅,而是“維持狀態(tài)”番挺。因?yàn)镠TTP協(xié)議是無(wú)狀態(tài)的,HTTP協(xié)議自身不對(duì)請(qǐng)求和響應(yīng)之間的通信狀態(tài)進(jìn)行保存屯掖,通俗來(lái)說(shuō)玄柏,服務(wù)器不知道用戶(hù)上一次做了什么,這嚴(yán)重阻礙了交互式Web應(yīng)用程序的實(shí)現(xiàn)贴铜。在典型的網(wǎng)上購(gòu)物場(chǎng)景中粪摘,用戶(hù)瀏覽了幾個(gè)頁(yè)面,買(mǎi)了一盒餅干和兩瓶飲料绍坝。最后結(jié)帳時(shí)徘意,由于HTTP的無(wú)狀態(tài)性,不通過(guò)額外的手段轩褐,服務(wù)器并不知道用戶(hù)到底買(mǎi)了什么椎咧,于是就誕生了cookie。它就是用來(lái)繞開(kāi)HTTP的無(wú)狀態(tài)性的“額外手段”之一把介。服務(wù)器可以設(shè)置或讀取cookie中包含信息勤讽,借此維護(hù)用戶(hù)跟服務(wù)器會(huì)話(huà)中的狀態(tài)。
在剛才的購(gòu)物場(chǎng)景中拗踢,當(dāng)用戶(hù)選購(gòu)了第一項(xiàng)商品脚牍,服務(wù)器在向用戶(hù)發(fā)送網(wǎng)頁(yè)的同時(shí),還發(fā)送了一段cookie巢墅,記錄著那項(xiàng)商品的信息诸狭。當(dāng)用戶(hù)訪(fǎng)問(wèn)另一個(gè)頁(yè)面,瀏覽器會(huì)把cookie發(fā)送給服務(wù)器君纫,于是服務(wù)器知道他之前選購(gòu)了什么驯遇。用戶(hù)繼續(xù)選購(gòu)飲料,服務(wù)器就在原來(lái)那段Cookie里追加新的商品信息蓄髓。結(jié)帳時(shí)妹懒,服務(wù)器讀取發(fā)送來(lái)的cookie就行了。
2.什么是cookie
cookie指某些網(wǎng)站為了辨別用戶(hù)身份而儲(chǔ)存在用戶(hù)本地終端上的數(shù)據(jù)(通常經(jīng)過(guò)加密)双吆。 cookie是服務(wù)端生成眨唬,客戶(hù)端進(jìn)行維護(hù)和存儲(chǔ)会前,存儲(chǔ)在內(nèi)存或者磁盤(pán)中。通過(guò)cookie,可以讓服務(wù)器知道請(qǐng)求是來(lái)源哪個(gè)客戶(hù)端匾竿,就可以進(jìn)行客戶(hù)端狀態(tài)的維護(hù)瓦宜,比如登陸后刷新,請(qǐng)求頭就會(huì)攜帶登陸時(shí)response header中的Set-Cookie,Web服務(wù)器接到請(qǐng)求時(shí)也能讀出cookie的值岭妖,根據(jù)cookie值的內(nèi)容就可以判斷和恢復(fù)一些用戶(hù)的信息狀態(tài)临庇。
簡(jiǎn)而言之,cookie 使基于無(wú)狀態(tài)的HTTP協(xié)議記錄穩(wěn)定的狀態(tài)信息成為了可能昵慌。
cookie 主要用于以下三個(gè)方面:
- 會(huì)話(huà)狀態(tài)管理(如用戶(hù)登錄狀態(tài)假夺、購(gòu)物車(chē)、游戲分?jǐn)?shù)或其它需要記錄的信息)
- 個(gè)性化設(shè)置(如用戶(hù)自定義設(shè)置斋攀、主題等)
- 瀏覽器行為跟蹤(如跟蹤分析用戶(hù)行為等)
3.cookie的原理及其構(gòu)成
第一次訪(fǎng)問(wèn)網(wǎng)站的時(shí)候已卷,瀏覽器發(fā)出請(qǐng)求,服務(wù)器端生成 cookie在響應(yīng)中通過(guò)Set-Cookie頭部告知客戶(hù)端(允許多個(gè)Set-Cookie頭部傳遞多個(gè)值)淳蔼,客戶(hù)端得到 cookie后,后續(xù)請(qǐng)求都會(huì)自動(dòng)將 cookie頭部攜帶至請(qǐng)求中發(fā)送給服務(wù)器(見(jiàn)下面例子)侧蘸,另外,cookie的過(guò)期時(shí)間鹉梨、域讳癌、路徑、有效期存皂、適用站點(diǎn)都可以根據(jù)需要來(lái)指定晌坤。
// 一個(gè)HTTP響應(yīng):
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value
Other-header: other-header-value
這個(gè)HTTP響應(yīng)會(huì)設(shè)置一個(gè)名為"name",值為"value"的cookie旦袋。名和值在發(fā)送時(shí)都會(huì)經(jīng)過(guò)URL編碼骤菠。瀏覽器會(huì)存儲(chǔ)這些會(huì)話(huà)信息,并在之后的每個(gè)請(qǐng)求中都會(huì)通過(guò)HTTP頭部cookie再將它們發(fā)回服務(wù)器猜憎,比如:
GET /index.jsl HTTP/1.1
Cookie: name=value
Other-header: other-header-value
cookie在瀏覽器中是由以下參數(shù)構(gòu)成的:
- name:唯一標(biāo)識(shí)cookie的名稱(chēng)娩怎。cookie名不區(qū)分大小寫(xiě)搔课,因此myCookie和MyCookie是同一個(gè)名稱(chēng)胰柑。不過(guò),實(shí)踐中最好將cookie名當(dāng)成區(qū)分大小寫(xiě)來(lái)對(duì)待爬泥,因?yàn)橐恍┓?wù)器軟件可能這樣對(duì)待它們柬讨。cookie名必須經(jīng)過(guò)URL編碼。
- value:存儲(chǔ)在cookie里的字符串值袍啡。這個(gè)值必須經(jīng)過(guò)URL編碼踩官。
-
Domain:cookie有效的域。發(fā)送到這個(gè)域的所有請(qǐng)求都會(huì)包含對(duì)應(yīng)的cookie境输。如果不指定蔗牡,默認(rèn)為文檔來(lái)源(由協(xié)議颖系、域名和端口共同定義),不包含子域名辩越。如果指定了
Domain
嘁扼,則一般包含子域名。因此黔攒,指定Domain
比省略它的限制要少趁啸。但是,當(dāng)子域需要共享有關(guān)用戶(hù)的信息時(shí)督惰,這可能會(huì)有所幫助不傅。例如,如果設(shè)置 Domain=mozilla.org赏胚,則 Cookie 也包含在子域名中(如developer.mozilla.org)访娶。 - Path:請(qǐng)求URL中包含這個(gè)路徑才會(huì)把cookie發(fā)送到服務(wù)器。
// 例如栅哀,設(shè)置 Path=/docs震肮,則以下地址都會(huì)匹配:
/docs
/docs/Web/
/docs/Web/HTTP
- Expires/Max-Age:設(shè)置cookie過(guò)期時(shí)間(Expires)或有效期(Max-Age)(即什么時(shí)間之后就不發(fā)送到服務(wù)器了)。簡(jiǎn)單名/值對(duì)形式的cookie只在當(dāng)前會(huì)話(huà)期間存在留拾,用戶(hù)關(guān)閉瀏覽器就會(huì)丟失戳晌。如果想讓cookie的生命周期超過(guò)單個(gè)瀏覽對(duì)話(huà),那就指定Expires/Max-Age痴柔,max-age優(yōu)先級(jí)高于expires沦偎。
- Secure:設(shè)置之后,只在使用SSL安全連接的情況下才會(huì)把cookie發(fā)送到服務(wù)器咳蔚。例如豪嚎,請(qǐng)求https://www.wrox.com會(huì)發(fā)送cookie,而請(qǐng)求http://www.wrox.com則不會(huì)谈火。
- HttpOnly:設(shè)置了 HttpOnly 屬性的 cookie 不能使用 JavaScript 經(jīng)由 Document.cookie 屬性侈询、XMLHttpRequest 和 Request APIs 進(jìn)行訪(fǎng)問(wèn),以防范跨站腳本攻擊(XSS)糯耍。
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; domain=.wrox.com; path=/; secure
Other-header: other-header-value
這里創(chuàng)建的cookie對(duì)所有wrox.com的子域及該域中的所有頁(yè)面有效(通過(guò)path=/指定)扔字。不過(guò),這個(gè)cookie只能在SSL連接上發(fā)送温技,因?yàn)樵O(shè)置了secure標(biāo)志革为。
要知道,域舵鳞、路徑震檩、過(guò)期時(shí)間和secure標(biāo)志用于告訴瀏覽器什么情況下應(yīng)該在請(qǐng)求中包含cookie。這些參數(shù)并不會(huì)隨請(qǐng)求發(fā)送給服務(wù)器蜓堕,實(shí)際發(fā)送的只有cookie的名/值對(duì)抛虏。
4.Javascript 中的cookie
一般說(shuō)來(lái)博其,cookie的生成方式主要有兩種,一種是上文提到的在響應(yīng)中通過(guò)Set-Cookie頭部告知客戶(hù)端迂猴;另外一種就是在JavaScript中可以通過(guò)document.cookie可以讀寫(xiě)cookie贺奠,如下:
//讀取瀏覽器中的cookie
console.log(document.cookie);
//寫(xiě)入cookie
document.cookie='myname=langlixingzhou;path=/;domain=.baidu.com';
在JavaScript中處理cookie比較麻煩,因?yàn)榻涌谶^(guò)于簡(jiǎn)單错忱,只有BOM的document.cookie屬性儡率。在設(shè)置值時(shí),可以通過(guò)document.cookie屬性設(shè)置新的cookie字符串以清。這個(gè)字符串在被解析后會(huì)添加到原有cookie中儿普。設(shè)置document.cookie不會(huì)覆蓋之前存在的任何cookie,除非設(shè)置了已有的cookie掷倔。要為創(chuàng)建的cookie指定額外的信息眉孩,只要像Set-Cookie頭部一樣直接在后面追加相同格式的字符串即可:
document.cookie = encodeURIComponent("name") + "=" +
encodeURIComponent("Nicholas") + "; domain=.wrox.com; path=/";
// 使用encodeURIComponent()對(duì)名稱(chēng)和值進(jìn)行編碼
5.cookie的缺陷
- cookie 不夠大
每個(gè)cookie的大小為4KB(名字和值都包含在這4KB之內(nèi)),對(duì)于復(fù)雜的存儲(chǔ)需求來(lái)說(shuō)是不夠用的勒葱。當(dāng) cookie 超過(guò) 4KB 時(shí)浪汪,它將面臨被裁切的命運(yùn)。這樣看來(lái)凛虽,cookie 只能用來(lái)存取少量的信息死遭。此外很多瀏覽器對(duì)一個(gè)站點(diǎn)的cookie個(gè)數(shù)也是有限制的(一般來(lái)說(shuō)不超過(guò)300個(gè)cookie)。
- 過(guò)多的 cookie 會(huì)帶來(lái)巨大的性能浪費(fèi)
cookie是與特定域綁定的凯旋。同一個(gè)域名下的所有請(qǐng)求呀潭,都會(huì)攜帶 cookie。大家試想至非,如果我們此刻僅僅是請(qǐng)求一張圖片或者一個(gè) CSS 文件钠署,我們也要攜帶一個(gè) cookie 跑來(lái)跑去(關(guān)鍵是 cookie 里存儲(chǔ)的信息并不需要),這是一件多么勞民傷財(cái)?shù)氖虑榛耐帧ookie 雖然小谐鼎,但隨著請(qǐng)求的疊加,這樣的不必要的 cookie 帶來(lái)的開(kāi)銷(xiāo)將是無(wú)法想象的趣惠。
cookie是用來(lái)維護(hù)用戶(hù)信息的狸棍,而域名(domain)下所有請(qǐng)求都會(huì)攜帶cookie,但對(duì)于靜態(tài)文件的請(qǐng)求信卡,攜帶cookie信息根本沒(méi)有用隔缀,此時(shí)可以通過(guò)CDN(存儲(chǔ)靜態(tài)文件的)的域名和主站的域名分開(kāi)來(lái)解決题造。
- 由于在HTTP請(qǐng)求中的cookie是明文傳遞的傍菇,所以安全性成問(wèn)題,除非用HTTPS界赔。
6.cookie與安全
[圖片上傳失敗...(image-ed8008-1649840506574)]
有兩種方法可以確保 cookie 被安全發(fā)送丢习,并且不會(huì)被意外的參與者或腳本訪(fǎng)問(wèn):Secure
屬性和HttpOnly
屬性牵触。
標(biāo)記為 Secure
的 cookie 只應(yīng)通過(guò)被 HTTPS 協(xié)議加密過(guò)的請(qǐng)求發(fā)送給服務(wù)端,因此可以預(yù)防中間人攻擊咐低。但即便設(shè)置了 Secure
標(biāo)記揽思,敏感信息也不應(yīng)該通過(guò) cookie 傳輸,因?yàn)?cookie 有其固有的不安全性见擦,Secure
標(biāo)記也無(wú)法提供確實(shí)的安全保障, 例如钉汗,可以訪(fǎng)問(wèn)客戶(hù)端硬盤(pán)的人可以讀取它。
從 Chrome 52 和 Firefox 52 開(kāi)始鲤屡,不安全的站點(diǎn)(http:
)無(wú)法使用cookie的 Secure
標(biāo)記损痰。
JavaScript Document.cookie API 無(wú)法訪(fǎng)問(wèn)帶有 HttpOnly
屬性的cookie;此類(lèi) cookie 僅作用于服務(wù)器酒来。例如卢未,持久化服務(wù)器端會(huì)話(huà)的 cookie 不需要對(duì) JavaScript 可用,而應(yīng)具有 HttpOnly
屬性堰汉。此預(yù)防措施有助于緩解跨站點(diǎn)腳本(XSS)攻擊辽社。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2019 07:28:00 GMT; Secure; HttpOnly
對(duì)cookie的限制及其特性決定了cookie并不是存儲(chǔ)大量數(shù)據(jù)的理想方式,讓“專(zhuān)業(yè)的人做專(zhuān)業(yè)的事情”翘鸭,Web Storage 出現(xiàn)了滴铅。
HTML5中新增了本地存儲(chǔ)的解決方案----Web Storage,這樣有了Web Storage后就乓,cookie能只做它應(yīng)該做的事情了—— 作為客戶(hù)端與服務(wù)器交互的通道失息,保持客戶(hù)端狀態(tài)。
二档址、Web Storage
Web Storage的目的是解決通過(guò)客戶(hù)端存儲(chǔ)不需要頻繁發(fā)送回服務(wù)器的數(shù)據(jù)時(shí)使用cookie的問(wèn)題盹兢。Web Storage API包含了兩個(gè)對(duì)象:localStorage和sessionStorage,本質(zhì)上是映射字符串鍵和值的對(duì)象化守伸。localStorage是永久存儲(chǔ)機(jī)制绎秒,sessionStorage是跨會(huì)話(huà)的存儲(chǔ)機(jī)制。這兩種瀏覽器存儲(chǔ)API提供了在瀏覽器中不受頁(yè)面刷新影響而存儲(chǔ)數(shù)據(jù)的兩種方式尼摹。
1见芹、Storage 對(duì)象
Window 對(duì)象的localStorage 和 sessionStorage 屬性引用的是 Storage對(duì)象。Storage對(duì)象用于保存名/值對(duì)數(shù)據(jù)蠢涝,直至存儲(chǔ)空間上限(由瀏覽器決定)玄呛。一般來(lái)說(shuō),客戶(hù)端數(shù)據(jù)的大小限制是按照每個(gè)源(協(xié)議和二、域和端口)來(lái)設(shè)置的徘铝,因此每個(gè)源有固定大小的數(shù)據(jù)存儲(chǔ)空間。不同瀏覽器給localStorage和sessionStorage設(shè)置了不同的空間限制,但大多數(shù)會(huì)限制為每個(gè)源5MB惕它。
Storage對(duì)象定義了如下方法:
- clear():刪除所有值怕午;不在Firefox中實(shí)現(xiàn)。
- getItem(name):取得給定name的值淹魄。
- key(index):取得給定數(shù)值位置的名稱(chēng)郁惜。
- removeItem(name):刪除給定name的名/值對(duì)。
- setItem(name, value):設(shè)置給定name的值甲锡。
Storage 對(duì)象中的鍵值對(duì)總是以字符串的形式存儲(chǔ)兆蕉,這意味著數(shù)值類(lèi)型會(huì)自動(dòng)轉(zhuǎn)化為字符串類(lèi)型。
2缤沦、sessionStorage
sessionStorage對(duì)象只存儲(chǔ)會(huì)話(huà)數(shù)據(jù)恨樟,這意味著數(shù)據(jù)只會(huì)存儲(chǔ)到瀏覽器關(guān)閉。這跟瀏覽器關(guān)閉時(shí)會(huì)消失的會(huì)話(huà)cookie類(lèi)似疚俱。存儲(chǔ)在sessionStorage中的數(shù)據(jù)不受頁(yè)面刷新影響劝术,可以在瀏覽器崩潰并重啟后恢復(fù)(取決于瀏覽器,F(xiàn)irefox和WebKit支持呆奕,IE不支持)养晋。
sessionStorage 特別應(yīng)該注意一點(diǎn)就是,即便是相同域名下的兩個(gè)頁(yè)面梁钾,只要它們不在同一個(gè)瀏覽器窗口中打開(kāi)绳泉,那么它們的 sessionStorage 數(shù)據(jù)便無(wú)法共享。
localStorage 與 sessionStorage 在 API 方面無(wú)異姆泻,這里我們以 sessionStorage 為例:
- 存儲(chǔ)數(shù)據(jù):setItem()
sessionStorage.setItem('user_name', 'juejin')
- 讀取數(shù)據(jù): getItem()
sessionStorage.getItem('user_name')
- 刪除某一鍵名對(duì)應(yīng)的數(shù)據(jù): removeItem()
sessionStorage.removeItem('user_name')
- 清空數(shù)據(jù)記錄:clear()
sessionStorage.clear()
雖然Web Storage存儲(chǔ)數(shù)據(jù)會(huì)帶來(lái)諸多便利零酪,但實(shí)際開(kāi)發(fā)中使用它也有不便之處:
- sessionStorage本身有API,但是只是簡(jiǎn)單的 key/value形式
- sessionStorage只存儲(chǔ)字符串,需要轉(zhuǎn)換成json對(duì)象
基于上面兩點(diǎn),開(kāi)發(fā)過(guò)程中會(huì)對(duì)它進(jìn)行封裝后再調(diào)用:
// 礙于文章篇幅拇勃,并未將完整代碼展示出來(lái)
// 想要獲取完整的代碼四苇,可以加wx:qqlcx55
// 將屬性存儲(chǔ)在某一模塊下
setItem(key,value,module_name){
if (module_name){
let val = this.getItem(module_name);
val[key] = value;
this.setItem(module_name, val);
}else{
let val = this.getStorage();
val[key] = value;
window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(val));
}
},
// 獲取某一個(gè)模塊下面的屬性
getItem(key,module_name){
if (module_name){
let val = this.getItem(module_name);
if(val) return val[key];
}
return this.getStorage()[key];
},
getStorage(){
return JSON.parse(window.sessionStorage.getItem(STORAGE_KEY) || '{}');
}
3、localStorage
localStorage 類(lèi)似 sessionStorage方咆,但其區(qū)別在于:存儲(chǔ)在 localStorage 的數(shù)據(jù)可以長(zhǎng)期保留月腋;而當(dāng)頁(yè)面會(huì)話(huà)結(jié)束(即當(dāng)頁(yè)面被關(guān)閉時(shí)),存儲(chǔ)在 sessionStorage 的數(shù)據(jù)會(huì)被清除 瓣赂。要訪(fǎng)問(wèn)同一個(gè)localStorage對(duì)象榆骚,頁(yè)面必須來(lái)自同一個(gè)域(子域不可以)、在相同的端口上使用相同的協(xié)議煌集。
考慮到 localStorage 的特點(diǎn)之一是持久妓肢,有時(shí)我們更傾向于用它來(lái)存儲(chǔ)一些內(nèi)容穩(wěn)定的資源。比如圖片內(nèi)容豐富的電商網(wǎng)站會(huì)用它來(lái)存儲(chǔ) Base64 格式的圖片字符串:
有的網(wǎng)站還會(huì)用它存儲(chǔ)一些不經(jīng)常更新的 CSS苫纤、JS 等靜態(tài)資源碉钠。
4纲缓、Web Storage與cookie 之間的區(qū)別
我們先來(lái)說(shuō)說(shuō)兩者的共同點(diǎn),然后再細(xì)說(shuō)下哪些地方有區(qū)別:
- 共同點(diǎn):都是保存在瀏覽器端放钦,且都遵循同源策略。
- 不同點(diǎn):在于生命周期與作用域的不同
作用域:localStorage只要在相同的協(xié)議恭金、相同的主機(jī)名操禀、相同的端口下,就能讀取/修改到同一份localStorage數(shù)據(jù)横腿。不過(guò)sessionStorage比localStorage更嚴(yán)苛一點(diǎn)颓屑,除了協(xié)議、主機(jī)名耿焊、端口外揪惦,還要求在同一窗口(也就是瀏覽器的標(biāo)簽頁(yè))下
[圖片上傳失敗...(image-2ae5d2-1649840506574)]
生命周期:localStorage 是持久化的本地存儲(chǔ),存儲(chǔ)在其中的數(shù)據(jù)是永遠(yuǎn)不會(huì)過(guò)期的罗侯,使其消失的唯一辦法是手動(dòng)刪除器腋;而 sessionStorage 是臨時(shí)性的本地存儲(chǔ),它是會(huì)話(huà)級(jí)別的存儲(chǔ)钩杰,當(dāng)會(huì)話(huà)結(jié)束(頁(yè)面被關(guān)閉)時(shí)纫塌,存儲(chǔ)內(nèi)容也隨之被釋放。
說(shuō)到底讲弄,Web Storage 是對(duì) Cookie 的拓展措左,它只能用于存儲(chǔ)少量的簡(jiǎn)單數(shù)據(jù)。當(dāng)遇到大規(guī)模的避除、結(jié)構(gòu)復(fù)雜的數(shù)據(jù)時(shí)怎披,Web Storage 也愛(ài)莫能助了。這時(shí)候我們就要清楚我們的終極大 boss——IndexedDB瓶摆!
四凉逛、IndexedDB
Indexed Database API簡(jiǎn)稱(chēng)IndexedDB,是瀏覽器中存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù)的一個(gè)方案群井。IndexedDB背后的思想是創(chuàng)造一套API鱼炒,方便JavaScript對(duì)象的存儲(chǔ)和獲取,同時(shí)也支持查詢(xún)和搜索蝌借。
IndexedDB是類(lèi)似于MySQL或Web SQL Database的數(shù)據(jù)庫(kù)昔瞧。與傳統(tǒng)數(shù)據(jù)庫(kù)最大的區(qū)別在于,IndexedDB使用對(duì)象存儲(chǔ)而不是表格保存數(shù)據(jù)菩佑。IndexedDB數(shù)據(jù)庫(kù)就是在一個(gè)公共命名空間下的一組對(duì)象存儲(chǔ)自晰,類(lèi)似于NoSQL風(fēng)格的實(shí)現(xiàn)。既然是數(shù)據(jù)庫(kù)了稍坯,那就不是 5M酬荞、10M 這樣小打小鬧級(jí)別了搓劫。理論上來(lái)說(shuō),IndexedDB 是沒(méi)有存儲(chǔ)上限的(一般來(lái)說(shuō)不會(huì)小于 250M)混巧。
1.IndexedDB的特點(diǎn)
- 鍵值對(duì)儲(chǔ)存枪向。
IndexedDB 內(nèi)部采用對(duì)象倉(cāng)庫(kù)(object store)存放數(shù)據(jù)。所有類(lèi)型的數(shù)據(jù)都可以直接存入咧党,包括 JavaScript 對(duì)象秘蛔。對(duì)象倉(cāng)庫(kù)中,數(shù)據(jù)以"鍵值對(duì)"的形式保存傍衡,每一個(gè)數(shù)據(jù)記錄都有對(duì)應(yīng)的主鍵深员,主鍵是獨(dú)一無(wú)二的,不能有重復(fù)蛙埂,否則會(huì)拋出一個(gè)錯(cuò)誤倦畅。
- 異步
IndexedDB的設(shè)計(jì)幾乎完全是異步的。為此绣的,大多數(shù)操作以請(qǐng)求的形式執(zhí)行叠赐,這些請(qǐng)求會(huì)異步執(zhí)行,產(chǎn)生成功的結(jié)果或錯(cuò)誤屡江。絕大多數(shù)IndexedDB操作要求添加onerror和onsuccess事件處理程序來(lái)確定輸出燎悍。IndexedDB 操作時(shí)不會(huì)鎖死瀏覽器,用戶(hù)依然可以進(jìn)行其他操作盼理,這與 localStorage 形成對(duì)比谈山,后者的操作是同步的。異步設(shè)計(jì)是為了防止大量數(shù)據(jù)的讀寫(xiě)宏怔,拖慢網(wǎng)頁(yè)的表現(xiàn)奏路。
- 支持事務(wù)。
IndexedDB 支持事務(wù)(transaction)臊诊,這意味著一系列操作步驟之中鸽粉,只要有一步失敗,整個(gè)事務(wù)就都取消抓艳,數(shù)據(jù)庫(kù)回滾到事務(wù)發(fā)生之前的狀態(tài)触机,不存在只改寫(xiě)一部分?jǐn)?shù)據(jù)的情況。
- 同源限制
IndexedDB 受到同源限制玷或,每一個(gè)數(shù)據(jù)庫(kù)對(duì)應(yīng)創(chuàng)建它的域名儡首。網(wǎng)頁(yè)只能訪(fǎng)問(wèn)自身域名下的數(shù)據(jù)庫(kù),而不能訪(fǎng)問(wèn)跨域的數(shù)據(jù)庫(kù)偏友。
- 儲(chǔ)存空間大
IndexedDB 的儲(chǔ)存空間比 localStorage 大得多蔬胯,一般來(lái)說(shuō)不少于 250MB,甚至沒(méi)有上限位他。
- 支持二進(jìn)制儲(chǔ)存氛濒。
IndexedDB 不僅可以?xún)?chǔ)存字符串产场,還可以?xún)?chǔ)存二進(jìn)制數(shù)據(jù)(ArrayBuffer 對(duì)象和 Blob 對(duì)象)。
2.IndexedDB 使用流程
在IndexedDB大部分操作并不是我們常用的調(diào)用方法舞竿,返回結(jié)果的模式京景,而是請(qǐng)求——響應(yīng)的模式。
接下來(lái)骗奖,我們遵循 MDN 推薦的操作模式确徙,通過(guò)一個(gè)基本的 IndexedDB 使用流程,旨在對(duì) IndexedDB 形成一個(gè)感性的認(rèn)知:
- 打開(kāi)/創(chuàng)建一個(gè) IndexedDB 數(shù)據(jù)庫(kù)(當(dāng)該數(shù)據(jù)庫(kù)不存在時(shí)重归,open 方法會(huì)直接創(chuàng)建一個(gè)名為 admin 新數(shù)據(jù)庫(kù))
// 后面的回調(diào)中米愿,我們可以通過(guò)event.target.result拿到數(shù)據(jù)庫(kù)實(shí)例
let db
// 參數(shù)1位數(shù)據(jù)庫(kù)名厦凤,參數(shù)2為版本號(hào)
const request = window.indexedDB.open("admin", 1)
// 使用IndexedDB失敗時(shí)的監(jiān)聽(tīng)函數(shù)
request.onerror = function(event) {
console.log('無(wú)法使用IndexedDB')
}
// 成功
request.onsuccess = function(event){
// 此處就可以獲取到db實(shí)例
db = event.target.result
console.log("你打開(kāi)了IndexedDB")
}
- 創(chuàng)建一個(gè) object store(object store 對(duì)標(biāo)到數(shù)據(jù)庫(kù)中的“表”單位)
// onupgradeneeded事件會(huì)在初始化數(shù)據(jù)庫(kù)/版本發(fā)生更新時(shí)被調(diào)用鼻吮,我們?cè)谒谋O(jiān)聽(tīng)函數(shù)中創(chuàng)建object store
request.onupgradeneeded = function(event){
let objectStore
// 如果同名表未被創(chuàng)建過(guò),則新建test表
if (!db.objectStoreNames.contains('test')) {
objectStore = db.createObjectStore('test', { keyPath: 'id' })
}
}
- 構(gòu)建一個(gè)事務(wù)來(lái)執(zhí)行一些數(shù)據(jù)庫(kù)操作较鼓,像增加或提取數(shù)據(jù)等
// 創(chuàng)建事務(wù)椎木,指定表格名稱(chēng)和讀寫(xiě)權(quán)限
const transaction = db.transaction(["test"],"readwrite")
// 拿到Object Store對(duì)象
const objectStore = transaction.objectStore("test")
// 向表格寫(xiě)入數(shù)據(jù)
objectStore.add({id: 1, name: 'juejin'})
- 通過(guò)監(jiān)聽(tīng)正確類(lèi)型的事件以等待操作完成。
// 操作成功時(shí)的監(jiān)聽(tīng)函數(shù)
transaction.oncomplete = function(event) {
console.log("操作成功")
}
// 操作失敗時(shí)的監(jiān)聽(tīng)函數(shù)
transaction.onerror = function(event) {
console.log("這里有一個(gè)Error")
}
3.Web Storage博烂、cookie 和 IndexedDB之間的區(qū)別
[圖片上傳失敗...(image-efc7d8-1649840506574)]
有了這些存儲(chǔ)手段香椎,就可以在客戶(hù)端通過(guò)使用JavaScript存儲(chǔ)可觀的數(shù)據(jù)。因?yàn)檫@些數(shù)據(jù)沒(méi)有加密禽篱,所以要注意不能使用它們存儲(chǔ)敏感信息畜伐。
總結(jié)
正是瀏覽器存儲(chǔ)、緩存技術(shù)的出現(xiàn)和發(fā)展躺率,為我們的前端應(yīng)用帶來(lái)了無(wú)限的轉(zhuǎn)機(jī)玛界。近年來(lái)基于存儲(chǔ)、緩存技術(shù)的第三方庫(kù)層出不絕悼吱,此外還衍生出了 PWA 這樣優(yōu)秀的 Web 應(yīng)用模型慎框。總結(jié)下本文幾個(gè)核心觀點(diǎn):
- Cookie 的本職工作并非本地存儲(chǔ)后添,而是“維持狀態(tài)”笨枯。
- Web Storage定義了兩個(gè)對(duì)象用于存儲(chǔ)數(shù)據(jù):sessionStorage和localStorage。前者用于嚴(yán)格保存瀏覽器一次會(huì)話(huà)期間的數(shù)據(jù)遇西,因?yàn)閿?shù)據(jù)會(huì)在瀏覽器關(guān)閉時(shí)被刪除馅精。后者用于會(huì)話(huà)之外持久保存數(shù)據(jù)。
- IndexedDB是類(lèi)似于SQL數(shù)據(jù)庫(kù)的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)機(jī)制粱檀。不同的是硫嘶,IndexedDB存儲(chǔ)的是對(duì)象,而不是數(shù)據(jù)表梧税。