手機上如今除了有原生 App,還能跑「WebApp」——它即開即用,用完即走。一個優秀的 WebApp 甚至能夠擁有和原生 App 媲美的功能和體驗。前端
我認爲,WebApp 就是咱們前端性能優化的產物,是咱們前端工程師對體驗不懈追求的結果,是 Web 網頁在性能上向 Native 應用的一次「宣戰」。數據庫
WebApp 優異的性能表現,要歸功於瀏覽器存儲技術的普遍應用——這其中除了咱們上節提到的緩存,本地存儲技術也功不可沒。瀏覽器
Cookie 的本職工做並不是本地存儲,而是「維持狀態」。緩存
在 Web 開發的早期,人們亟需解決的一個問題就是狀態管理的問題:HTTP 協議是一個無狀態協議,服務器接收客戶端的請求,返回一個響應,故事到此就結束了,服務器並無記錄下關於客戶端的任何信息。那麼下次請求的時候,如何讓服務器知道「我是我」呢?性能優化
在這樣的背景下,Cookie 應運而生。bash
Cookie 說白了就是一個存儲在瀏覽器裏的一個小小的文本文件,它附着在 HTTP 請求上,在瀏覽器和服務器之間「飛來飛去」。它能夠攜帶用戶信息,當服務器檢查 Cookie 的時候,即可以獲取到客戶端的狀態。服務器
關於 Cookie 的詳細內容,咱們能夠在 Chrome 的 Application 面板中查看到:前端工程師
如你們所見,Cookie 以鍵值對的形式存在。dom
你們知道,Cookie 是有體積上限的,它最大隻能有 4KB。當 Cookie 超過 4KB 時,它將面臨被裁切的命運。這樣看來,Cookie 只能用來存取少許的信息。前端性能
Cookie 是緊跟域名的。咱們經過響應頭裏的 Set-Cookie 指定要存儲的 Cookie 值。默認狀況下,domain 被設置爲設置 Cookie 頁面的主機名,咱們也能夠手動設置 domain 的值:
Set-Cookie: name=xiuyan; domain=xiuyan.me
複製代碼
同一個域名下的全部請求,都會攜帶 Cookie。你們試想,若是咱們此刻僅僅是請求一張圖片或者一個 CSS 文件,咱們也要攜帶一個 Cookie 跑來跑去(關鍵是 Cookie 裏存儲的信息我如今並不須要),這是一件多麼勞民傷財的事情。Cookie 雖然小,請求卻能夠有不少,隨着請求的疊加,這樣的沒必要要的 Cookie 帶來的開銷將是沒法想象的。
隨着前端應用複雜度的提升,Cookie 也漸漸演化爲了一個「存儲多面手」——它不只僅被用於維持狀態,還被塞入了一些亂七八糟的其它信息,被迫承擔起了本地存儲的「重任」。在沒有更好的本地存儲解決方案的年代裏,Cookie 小小的身體裏承載了 4KB 內存所不能承受的壓力。
爲了彌補 Cookie 的侷限性,讓「專業的人作專業的事情」,Web Storage 出現了。
Web Storage 是 HTML5 專門爲瀏覽器存儲而提供的數據存儲機制。它又分爲 Local Storage 與 Session Storage。這兩組概念很是相近,咱們不妨先理解它們之間的區別,再對它們的共性進行研究。
二者的區別在於生命週期與做用域的不一樣。
生命週期:Local Storage 是持久化的本地存儲,存儲在其中的數據是永遠不會過時的,使其消失的惟一辦法是手動刪除;而 Session Storage 是臨時性的本地存儲,它是會話級別的存儲,當會話結束(頁面被關閉)時,存儲內容也隨之被釋放。
做用域:Local Storage、Session Storage 和 Cookie 都遵循同源策略。但 Session Storage 特別的一點在於,即使是相同域名下的兩個頁面,只要它們不在同一個瀏覽器窗口中打開,那麼它們的 Session Storage 內容便沒法共享。
存儲容量大: Web Storage 根據瀏覽器的不一樣,存儲容量能夠達到 5-10M 之間。
僅位於瀏覽器端,不與服務端發生通訊。
Web Storage 保存的數據內容和 Cookie 同樣,是文本內容,以鍵值對的形式存在。Local Storage 與 Session Storage 在 API 方面無異,這裏咱們以 localStorage 爲例:
localStorage.setItem('user_name', 'xiuyan')
複製代碼
localStorage.getItem('user_name')
複製代碼
localStorage.removeItem('user_name')
複製代碼
localStorage.clear()
複製代碼
Local Storage 在存儲方面沒有什麼特別的限制,理論上 Cookie 沒法勝任的、能夠用簡單的鍵值對來存取的數據存儲任務,均可以交給 Local Storage 來作。
這裏給你們舉個例子,考慮到 Local Storage 的特色之一是持久,有時咱們更傾向於用它來存儲一些內容穩定的資源。好比圖片內容豐富的電商網站會用它來存儲 Base64 格式的圖片字符串:
有的網站還會用它存儲一些不常常更新的 CSS、JS 等靜態資源。
Session Storage 更適合用來存儲生命週期和它同步的會話級別的信息。這些信息只適用於當前會話,當你開啓新的會話時,它也須要相應的更新或釋放。好比微博的 Session Storage 就主要是存儲你本次會話的瀏覽足跡:
lasturl 對應的就是你上一次訪問的 URL 地址,這個地址是即時的。當你切換 URL 時,它隨之更新,當你關閉頁面時,留着它也確實沒有什麼意義了,乾脆釋放吧。這樣的數據用 Session Storage 來處理再合適不過。
這樣看來,Web Storage 確實也夠強大了。那麼 Web Storage 是否能 hold 住全部的存儲場景呢?
答案是否認的。你們也看到了,Web Storage 是一個從定義到使用都很是簡單的東西。它使用鍵值對的形式進行存儲,這種模式有點相似於對象,卻甚至連對象都不是——它只能存儲字符串,要想獲得對象,咱們還須要先對字符串進行一輪解析。
說到底,Web Storage 是對 Cookie 的拓展,它只能用於存儲少許的簡單數據。當遇到大規模的、結構複雜的數據時,Web Storage 也心有餘而力不足了。這時候咱們就要清楚咱們的終極大 boss——IndexDB!
IndexDB 是一個運行在瀏覽器上的非關係型數據庫。既然是數據庫了,那就不是 5M、10M 這樣小打小鬧級別了。理論上來講,IndexDB 是沒有存儲上限的(通常來講不會小於 250M)。它不只能夠存儲字符串,還能夠存儲二進制數據。
IndexDB 從推出之日起,其優質教程就層出不絕,咱們今天再也不着重講解它的詳細操做。接下來,咱們遵循 MDN 推薦的操做模式,經過一個基本的 IndexDB 使用流程,旨在對 IndexDB 造成一個感性的認知:
// 後面的回調中,咱們能夠經過event.target.result拿到數據庫實例
let db
// 參數1位數據庫名,參數2爲版本號
const request = window.indexedDB.open("xiaoceDB", 1)
// 使用IndexDB失敗時的監聽函數
request.onerror = function(event) {
console.log('沒法使用IndexDB')
}
// 成功
request.onsuccess = function(event){
// 此處就能夠獲取到db實例
db = event.target.result
console.log("你打開了IndexDB")
}
複製代碼
// onupgradeneeded事件會在初始化數據庫/版本發生更新時被調用,咱們在它的監聽函數中建立object store
request.onupgradeneeded = function(event){
let objectStore
// 若是同名表未被建立過,則新建test表
if (!db.objectStoreNames.contains('test')) {
objectStore = db.createObjectStore('test', { keyPath: 'id' })
}
}
複製代碼
// 建立事務,指定表格名稱和讀寫權限
const transaction = db.transaction(["test"],"readwrite")
// 拿到Object Store對象
const objectStore = transaction.objectStore("test")
// 向表格寫入數據
objectStore.add({id: 1, name: 'xiuyan'})
複製代碼
// 操做成功時的監聽函數
transaction.oncomplete = function(event) {
console.log("操做成功")
}
// 操做失敗時的監聽函數
transaction.onerror = function(event) {
console.log("這裏有一個Error")
}
複製代碼
經過上面的示例你們能夠看出,在 IndexDB 中,咱們能夠建立多個數據庫,一個數據庫中建立多張表,一張表中存儲多條數據——這足以 hold 住複雜的結構性數據。IndexDB 能夠看作是 LocalStorage 的一個升級,當數據的複雜度和規模上升到了 LocalStorage 沒法解決的程度,咱們毫無疑問能夠請出 IndexDB 來幫忙。
瀏覽器緩存/存儲技術的出現和發展,爲咱們的前端應用帶來了無限的起色。近年來基於緩存/存儲技術的第三方庫層出不絕,此外還衍生出了 PWA 這樣優秀的 Web 應用模型。能夠說,現代前端應用,尤爲是移動端應用,之因此能夠發展到在體驗上叫板 Native 的地步,主要就是仰仗緩存/存儲立下的汗馬功勞。