JavaScript是如何工做的:存儲引擎+如何選擇合適的存儲API

這是專門探索 JavaScript 及其所構建的組件的系列文章的第 16 篇。javascript

想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!前端

若是你錯過了前面的章節,能夠在這裏找到它們:java

  1. JavaScript 是如何工做的:引擎,運行時和調用堆棧的概述!
  2. JavaScript 是如何工做的:深刻V8引擎&編寫優化代碼的5個技巧!
  3. JavaScript 是如何工做的:內存管理+如何處理4個常見的內存泄漏!
  4. JavaScript 是如何工做的:事件循環和異步編程的崛起+ 5種使用 async/await 更好地編碼方式!
  5. JavaScript 是如何工做的:深刻探索 websocket 和HTTP/2與SSE +如何選擇正確的路徑!
  6. JavaScript 是如何工做的:與 WebAssembly比較 及其使用場景!
  7. JavaScript 是如何工做的:Web Workers的構建塊+ 5個使用他們的場景!
  8. JavaScript 是如何工做的:Service Worker 的生命週期及使用場景!
  9. JavaScript 是如何工做的:Web 推送通知的機制!
  10. JavaScript是如何工做的:使用 MutationObserver 跟蹤 DOM 的變化!
  11. JavaScript是如何工做的:渲染引擎和優化其性能的技巧!
  12. JavaScript是如何工做的:深刻網絡層 + 如何優化性能和安全!
  13. JavaScript是如何工做的:CSS 和 JS 動畫底層原理及如何優化它們的性能!
  14. JavaScript的如何工做的:解析、抽象語法樹(AST)+ 提高編譯速度5個技巧!
  15. JavaScript是如何工做的:深刻類和繼承內部原理+Babel和 TypeScript 之間轉換!

概述

在設計 Web 應用程序時,爲本地瀏覽器選擇合適的存儲機制相當重要, 一個好的存儲引擎能夠確保可靠地保存信息,減小帶寬,提升響應能力。正確的存儲緩存策略是實現離線移動 Web 體驗的核心構建塊,同時也大大的提升了用戶體驗。git

在本章中,討論可選擇的存儲 Api 和服務,並提供一些在構建 Web應用程序,該使用哪一種存儲引擎。github

數據模型

數據存儲模型肯定數據在內部的組織方式,這會影響 Web 應用程序的整個設計,合理的數據模式會讓 Web 應用程序在完成它應有的任務下還能讓運行速度更加高效。對於全部與工程相關的問題,沒有存在最好的解決方法,也沒有適用於全部問題的解決方案,不一樣場景下有不一樣的選擇。因此,來看看可選擇的數據模型:web

  • 結構化: 存儲在具備預約義字段的表中的數據(這是典型的基於 SQL 的數據庫管理系統)適行靈活的動態查詢。瀏覽器中結構化數據存儲的一個表明的例子是 IndexedDB
  • Key/Value: 鍵/值 數據存儲和相關的 NoSQL 數據庫提供了存儲和檢索由惟一鍵索引的非結構化數據的能力。鍵/值 數據存儲相似於哈希表,由於它們容許對索引的不透明數據進行長時間訪問。 鍵/值 數據存儲的表明例子是瀏覽器中的 Cache API 和服務器上的 Apache Cassandra
Apache Cassandra 是一套開源分佈式數據庫管理系統,由Facebook開發,用於儲存特別大的數據。
  • 字節流:這個簡單的模型將數據存儲爲長度不透明的字節字符串變量,將任何形式的內部組織留給應用層。這個模型特別適合於文件系統和其餘分層組織的數據塊。字節流數據存儲的表明例子包括文件系統和雲存儲服務。

持久化

web 應用程序的存儲方法能夠根據數據持久化的時間段進行劃分:數據庫

  • 會話持久化: 該類別中的數據僅在單個 Web 會話或瀏覽器選項卡保持激活狀態時才持久,具備會話持久性的存儲機制的一個示例是 Session Storage API
  • 設備的持久化: 此類別中的數據在特定設備上跨會話和瀏覽器選項卡/窗口持久化,具備設備持久化的存儲機制的一個示例是 Cache API
  • 此類中的數據跨會話和設備持久化。所以,它是最健壯的數據持久性形式。可是,它不能存儲在設備自己上,這意味須要在某種服務器端存儲。在這裏不會詳細討論它,由於本文的重點是在設備自己上存儲數據。

瀏覽器中的數據持久化

如今,有至關多的瀏覽器 Api 用來存儲數據。這裏將逐一介紹其中的一些及它們的區別,以便後續咱們可以容合理的選擇使用。編程

然而,在選擇如何持久化數據以前,有幾件事須要考慮。固然,有必要知道的的第一件事是你的 Web 應用程序應用場景是什麼,以及之後如何迭代和豐富。即便你知道了這些,最終也會有幾個選擇。因此,如下是須要了解的:segmentfault

  • 瀏覽器支持  —  標準化和完善的 API 更值得咱們選擇,由於它們每每壽命更長,支持更普遍, 這些API 還享有更豐富的文檔和開發人員社區。
  • 事務 — 有時,相關存儲操做的集合原子地成功或失敗是很重要的。傳統上,數據庫使用事務模型支持此功能,其中相關更新能夠分組到任意單元中。
  • 同步/異步 — 有些存儲 Api 是同步的,由於存儲或檢索請求會阻塞當前活動的線程,直到請求完成。使用同步存儲 API 會阻塞主線程,併爲 Web 應用程序的 UI 建立凍結體驗。若是可能,使用異步API。

比較

在本節中,瞭解決 Web 開發人員的當前可用存儲 Api,並從各個維度上進行比較。api

圖片描述

文件系統API

圖片描述

經過 FileSystem API, Web 應用就能夠建立、讀取、導航用戶本地文件系統中的沙盒部分以及向其中寫入數據。

API 被分爲如下不一樣的主題:

  • 讀取和處理文件:File/Blob、FileList、FileReader
  • 建立和寫入:BlobBuilder、FileWriter
  • 目錄和文件系統訪問:DirectoryReader、FileEntry/DirectoryEntry、LocalFileSystem

FileSystem API 是非標準 API。在發佈環境因慎重使用,由於並是全部的瀏覽器都支持,實現方式可能存在很大的不兼容性,而且在未來可能也會發生變化。

請求文件系統

網絡應用可經過調用 window.requestFileSystem() 請求對沙盒文件系統的訪問權限:

// Note: The file system has been prefixed as of Google Chrome 12:
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(type, size, successCallback, opt_errorCallback)

type:文件存儲是否應該是持久的。可能的值包括 window.TEMPORARYwindow.PERSISTENT。經過 TEMPORARY 存儲的數據可由瀏覽器自行決定刪除(例如在須要更多空間的狀況下),要清除PERSISTENT 存儲,必須得到用戶或應用的明確受權,而且須要用戶向你的應用授予配額。

size: 應用須要用於存儲的大小 (以字節爲單位)。

successCallback:文件系統請求成功時調用的回調,其參數爲 FileSystem 對象。

opt_errorCallback: 用於處理錯誤或獲取文件系統的請求遭到拒絕時可選的回調,其參數爲 FileError 對象。

若是你是首次調用 requestFileSystem(),系統會爲你的應用建立新的存儲。請注意,這是沙箱文件系統,也就是說,一個網絡應用沒法訪問另外一個應用的文件。

在訪問文件系統以後,能夠對文件和目錄執行大多數標準操做。

與其餘存儲類型相比,文件系統是一個徹底不一樣的存儲類型,由於它的旨在知足數據庫,很不能很好地服務的客戶端存儲用例。一般,這些應用程序處理大型二進制blob或與瀏覽器上下文以外的應用程序共享數據。

如下使用文件系統 API 的幾個示例:

  • 有上傳的應用

    • 當你選擇一個文件或目錄進行上傳時,你能夠賦值文件到一個本地沙盒並一次上傳一個塊。
    • 應用能夠在一次中斷後從新上傳,中斷可能包括瀏覽器被關閉或崩潰,鏈接中斷,或電腦被關閉。
  • 視頻遊戲或其餘使用大量媒體資源的應用

    • 用下載一個或多個大壓縮包並在本地將他們解壓到一個文件目錄中。
    • 應用能在後臺預取資源,從而讓用戶可以進入下一項工做或遊戲等級,而不須要等待下載。
  • 音頻或照片編輯器使用線下訪問或本地緩存

    • 應用能夠分段寫入文件(例如只覆蓋ID3/EXIF標籤而不是整個文件)。
  • 線下視頻瀏覽

    • 應用能夠訪問只下載了部分的文件。
  • 線下網絡郵件客戶端

    • 客戶端下載附件並在本地存儲它們。
    • 客戶端緩存附件用於稍後的上傳。

目前瀏覽器對文件系統 API 的支持:

圖片描述

Local storage

圖片描述

只讀的 localStorage 容許你訪問一個 Document 的遠端(origin)對象 Storage;其存儲的數據能在跨瀏覽器會話保留。 localStorage 相似 sessionStorage,其區別在於:存儲在 localStorage 的數據能夠長期保留;而當頁面會話結束——也就是說當頁面被關閉時,存儲在 sessionStorage 的數據會被清除 。

應注意不管數據存儲在 localStorage 仍是 sessionStorage ,它們都特定於頁面的協議

另外,localStorage 中的鍵值對老是以字符串的形式存儲。

當前瀏覽器對API的支持:

圖片描述

Session storage

圖片描述

sessionStorage 屬性容許你訪問一個 session Storage 對象。它與 localStorage 類似,不一樣之處在於 localStorage 裏面存儲的數據沒有過時時間設置,而存儲在 sessionStorage 裏面的數據在頁面會話結束時會被清除。頁面會話在瀏覽器打開期間一直保持,而且從新加載或恢復頁面仍會保持原來的頁面會話。在新標籤或窗口打開一個頁面時會在頂級瀏覽上下文中初始化一個新的會話,這點和 session cookies 的運行方式不一樣。

應該注意的是,不管是 localStorage 仍是 sessionStorage 中保存的數據都僅限於該頁面的協議

當前瀏覽器對API的支持:

圖片描述

Cookies

圖片描述

HTTP Cookie(也叫Web Cookie或瀏覽器Cookie)是服務器發送到用戶瀏覽器並保存在本地的一小塊數據,它會在瀏覽器下次向同一服務器再發起請求時被攜帶併發送到服務器上。一般,它用於告知服務端兩個請求是否來自同一瀏覽器,如保持用戶的登陸狀態。Cookie 使基於無狀態的 HTTP 協議記錄穩定的狀態信息成爲了可能。

Cookie主要用於如下三個方面:

  • 會話狀態管理(如用戶登陸狀態、購物車、遊戲分數或其它須要記錄的信息)
  • 個性化設置(如用戶自定義設置、主題等)

* 瀏覽器行爲跟蹤(如跟蹤分析用戶行爲等)

Cookie曾一度用於客戶端數據的存儲,因當時並無其它合適的存儲辦法而做爲惟一的存儲手段,但如今隨着現代瀏覽器開始支持各類各樣的存儲方式,Cookie漸漸被淘汰。因爲服務器指定Cookie後,瀏覽器的每次請求都會攜帶Cookie數據,會帶來額外的性能開銷(尤爲是在移動環境下)。

cookie 類型有兩種:

  • 會話 Cookie  —  瀏覽器關閉以後它會被自動刪除,也就是說它僅在會話期內有效。會話期Cookie不須要指定過時時間(Expires)或者有效期(Max-Age)。須要注意的是,有些瀏覽器提供了會話恢復功能,這種狀況下即便關閉了瀏覽器,會話期Cookie也會被保留下來,就好像瀏覽器歷來沒有關閉同樣。
  • 持久 Cookie — 和關閉瀏覽器便失效的會話期Cookie不一樣,持久性Cookie能夠指定一個特定的過時時間(Expires)或有效期(Max-Age)。

當機器處於不安全環境時,切記不能經過HTTP Cookie存儲、傳輸敏感信息,且全部瀏覽器都普遍支持cookie。

Cache

圖片描述

Cache 接口爲緩存的 Request/Response 對象對提供存儲機制,例如,做爲 ServiceWorker 生命週期的一部分。請注意,Cache 接口像 workers 同樣,是暴露在 window 做用域下的。儘管它被定義在 service worker 的標準中, 可是它沒必要必定要配合 service worker 使用.

一個域能夠有多個命名 Cache 對象。你須要在你的腳本 (例如,在 ServiceWorker 中)中處理緩存更新的方式。除非明確地更新緩存,不然緩存將不會被更新;除非刪除,不然緩存數據不會過時。使用 CacheStorage.open(cacheName) 打開一個Cache 對象,再使用 Cache 對象的方法去處理緩存.

你須要按期地清理緩存條目,由於每一個瀏覽器都硬性限制了一個域下緩存數據的大小。緩存配額使用估算值,可使用 StorageEstimate API 得到。瀏覽器盡其所能去管理磁盤空間,但它有可能刪除一個域下的緩存數據。瀏覽器要麼自動刪除特定域的所有緩存,要麼所有保留。確保按名稱安裝版本緩存,並僅從能夠安全操做的腳本版本中使用緩存。查看 Deleting old caches 獲取更多信息.

CacheStorage 接口表示 Cache 對象的存儲。

  • 它提供了一個 ServiceWorker,其它類型worker或者 window 範圍內能夠訪問到的全部命名cache的主目錄(它並非必定要和 service workers 一塊兒使用,即便它是在 service workers 規範中定義的),並維護一份字符串名稱到相應 Cache 對象的映射。
  • 使用 CacheStorage.open() 獲取 Cache 實例。
  • 使用 CacheStorage.match() 檢查給定的 Request 是不是 CacheStorage 對象跟蹤的任何 Cache 對象中的鍵。

你能夠經過 caches 屬性訪問 CacheStorage .

IndexedDB

圖片描述

IndexedDB 是一種在用戶瀏覽器中持久存儲數據的方法。由於它容許你建立具備豐富查詢功能的 Web 應用程序,不管網絡可用性如何,這些應用程序均可以在線和離線工做。IndexedDB 對於存儲大量數據的應用程序(例如,借出庫中的 DVD 目錄)和不須要持久 internet 鏈接才能工做的應用程序(例如,郵件客戶機、待辦事項列表和記事本)很是有用。

在本文中,會更詳細地討論存儲數據庫,由於其他的存儲 Api 都是衆所周知的。另外,隨着 Web 應用程序的複雜性愈來愈高,IndexedDB 也愈來愈受歡迎。

IndexedDB的內部結構

IndexedDB 經過「鍵」來存儲和檢索對象。對數據庫所作的全部更改都發生在事務中,像大多數 Web 存儲解決方案同樣,IndexedDB 遵循同源策略。所以,雖然能夠訪問域中存儲的數據,可是不能跨不一樣的域訪問數據。

IndexedDB 是一個 異步 API,能夠在大多數上下文中使用,包括 WebWorkers。它過去也包括一個同步版本,供 Web 開發者使用,可是因爲 Web 社區對它缺少興趣,因此從規範中刪除了這個版本。

IndexedDB 曾經有一個與之競爭的規範,稱爲 WebSQL 數據庫,可是 W3C 棄用了它。雖然 IndexedDB 和WebSQL 都是存儲解決方案,但它們提供的功能不一樣。WebSQL 數據庫是一個關係數據庫訪問系統,而IndexedDB 是一個索引表系統。

不要一開始就使用 IndexedDB,這依賴於你對其餘類型數據庫的假設。相反,應該仔細閱讀文檔,如下是一些須要牢記的基本概念:

  • IndexedDB 數據庫使用 key-value 鍵值對儲存數據  —  values 數據能夠是結構很是複雜的對象,key能夠是對象自身的屬性。你能夠對對象的某個屬性建立索引(index)以實現快速查詢和列舉排序。key能夠是二進制對象。
  • IndexedDB 是事務模式的數據庫 —  任何操做都發生在事務(transaction)中。 IndexedDB API提供了索引(indexes)、表(tables)、指針(cursors)等等,可是全部這些必須是依賴於某種事務的。所以,你不能在事務外執行命令或者打開指針。事務(transaction)有生存週期,在生存週期之後使用它會報錯。而且,事務(transaction)是自動提交的,不能夠手動提交。
  • The IndexedDB API 基本上是異步的 — IndexedDB 的 API 不經過 return 語句返回數據,而是須要你提供一個回調函數來接受數據。執行 API 時,你不以同步(synchronous)方式對數據庫進行「存儲」和「讀取」操做,而是向數據庫發送一個操做「請求」。當操做完成時,數據庫會以DOM事件的方式通知你,同時事件的類型會告訴你這個操做是否成功完成。這個過程聽起來會有些複雜,可是裏面是有明智的緣由的。這個和 XMLHttpRequest 請求是相似的。
  • IndexedDB數據庫「請求」無處不在 — 每個「請求」都包含 onsuccessonerror 事件屬性,同時你還對 「事件」 調用 addEventListener()removeEventListener()。「請求」 還包括 readyStateresulterrorCode 屬性,用來表示「請求」的狀態。result 屬性尤爲神奇,他能夠根據「請求」生成的方式變成不一樣的東西,例如:IDBCursor 實例、剛插入數據庫的數值對應的鍵值(key)等。
  • IndexedDB是面向對象的 — indexedDB 不是用二維表來表示集合的關係型數據庫,這一點很是重要,將影響你設計和創建你的應用程序。
  • indexedDB 不使用結構化查詢語言(SQL) — 它經過索引(index)所產生的指針(cursor)來完成查詢操做,從而使你能夠迭代遍歷到結果集合。若是你不熟悉NoSQL系統,能夠參考維基百科相關文章
  • IndexedDB遵循同源(same-origin)策略 — 「源」指腳本所在文檔URL的域名、應用層協議和端口。每個「源」都有與其相關聯的數據庫。在同一個「源」內的全部數據庫都有惟1、可區別的名稱。

IndexedDB侷限性

如下狀況不適合使用IndexedDB

  • 全球多種語言混合存儲。國際化支持很差。須要本身處理。
  • 和服務器端數據庫同步。你得本身寫同步代碼。
  • 全文搜索。IndexedDB 接口沒有相似 SQL 語句中 LIKE 的功能。

注意,在如下狀況下,數據庫可能被清除:

  • 用戶請求清除數據。
  • 瀏覽器處於隱私模式。最後退出瀏覽器的時候,數據會被清除。
  • 硬盤等存儲設備的容量到限。
  • 數據損壞。
  • 進行與特性不兼容的操做。
  • 確切的環境和瀏覽器特性會隨着時間改變,但瀏覽器廠商一般會遵循盡最大努力保留數據的理念。

確切的環境和瀏覽器特性會隨着時間改變,但瀏覽器廠商一般會遵循盡最大努力保留數據的理念。

圖片描述

選擇正確的存儲API

如前所述,最好選擇儘量多的瀏覽器普遍支持的 Api,並提供異步調用模型,以最大限度地提升 UI 響應能力。這些標準天然會致使如下技術選擇:

  • 對於離線存儲,請使用 Cache API。任何支持建立離線應用程序所需的 Service Worker technology 的瀏覽器均可以使用這個 API,Cache API 很是適合存儲與已知 URL 關聯的資源。
  • 要存儲應用程序狀態和用戶生成的內容,請使用IndexedDB。這使得用戶能夠在更多的瀏覽器中離線工做,而不只僅是那些支持緩存API的瀏覽器。


原文:

https://blog.sessionstack.com...

這篇主要一些內容原做者大部分是經過 MDN 整理的組合的,我也是根據中文的 MND 整理的組合。

你的點贊是我持續分享好東西的動力,歡迎點贊!

歡迎加入前端你們庭,裏面會常常分享一些技術資源。

clipboard.png

相關文章
相關標籤/搜索