LocalForage - indexDB driver代碼解析

一创泄、 indexDB簡介

indexDB是為了解決h5的localStorage在容量敢靡,存儲類型上的限制而提出的web客戶端數(shù)據(jù)庫素标,與localStorage最大的不同在于其更多的從數(shù)據(jù)庫的角度對API進行了設計猪瞬,已在safari7.1, IE10膀懈,chrome23以上的版本中得到實現(xiàn)仅仆。該API規(guī)范提出了以下對象

  • 數(shù)據(jù)庫:IDBDatabase 對象
  • 對象倉庫:IDBObjectStore 對象
  • 索引: IDBIndex 對象
  • 事務: IDBTransaction 對象
  • 操作請求:IDBRequest 對象
  • 指針: IDBCursor 對象
  • 主鍵集合:IDBKeyRange 對象

indexDB的工作邏輯參照下圖所示(實線同步器赞,虛線異步,下同):
  1. 首先通過indexDB.open指定名稱和版本打開數(shù)據(jù)庫墓拜,獲取IDBRequst對象港柜,后續(xù)過程為異步
  2. 如果版本號增加則會發(fā)生onupgradeneeded事件咳榜,否則僅發(fā)生success事件夏醉,可在該事件中通過request.result或e.target.result獲取到IDBDatabase對象,即數(shù)據(jù)庫本身涌韩;
  3. 獲取數(shù)據(jù)庫后畔柔,可通過objectStoreName.contains檢查數(shù)據(jù)庫存儲的表,如果沒有需要查詢的表可通過createObjectStore新建表贸辈,新建時如不指明keyPath則默認為id字段遞增释树;如果存在可以直接通過objectStore獲取指定的IDBObjectStore表對象;
  4. 獲取表后擎淤,可通過createIndex建立索引奢啥;
  5. 如需對表進行增刪改查操作,必須借由事務API進行嘴拢,需要調用db.transcation(storeNames桩盲,operationType)獲取指定表序列執(zhí)行指定操作的IDBTransaction對象,operationType目前僅有readwrite和readonly兩種席吴;
  6. 獲取事務對象后赌结,先通過objectStore指定操作的表,然后通過add/delete/put/get執(zhí)行相應的增刪改查操作孝冒,該操作為異步柬姚,只可以通過注冊success和error的事件監(jiān)聽函數(shù)執(zhí)行回調。

二庄涡、代碼解析

以下內容為對indexDB驅動相關代碼的流程分析量承,以及相關兼容代碼的原理,可供indexDB開發(fā)者作為參考,localForage結合promise對于indexDB做了一系列的異步事務調度管理策略撕捍,確保多forage實例拿穴,多數(shù)據(jù)庫,多objectStorage表可協(xié)同工作忧风,不會引發(fā)數(shù)據(jù)庫一致性問題默色。

1. blob兼容

blob兼容主要分為兩種情況:

  1. blob文件能否存入indexDB (chrome < 37 || android < 5不支持)
  2. blob文件從indexDB取出使用是否會出現(xiàn)問題 (chrome 37~42 存在解碼問題)

相關參考信息:

localForage的兼容方案如下圖所示:

  1. 針對第一種情況,localForage在每次建立新的db時都會專門新建一個名為local-forage-detect-blob-support的表(額外建表為防止調用iterate或length等接口產(chǎn)生干擾)來嘗試存儲一個blob文件狮腿,若該過程失敗則直接返回false腿宰,緩存到supportsBlobs變量中
  2. 針對第二種情況,在事務的oncomplete事件中檢查瀏覽器版本蚤霞,如果為chrome 43以上版本或edge(edge接入谷歌內核后需單獨在userAgent里check)或其他瀏覽器酗失,則可完美支持,返回ture昧绣,否則返回false规肴,緩存到supportsBlobs
  3. 之后檢查文件類型支持時只需訪問supportsBlobs本地變量即可

對于無法完美支持blob存儲indexDB的情況, localForage采用的向下兼容策略為:

  1. 使用FileReader和btoa將二進制文件轉換為base64二進制字符串進行存儲,并添加一個轉換的標記
  2. 取用時通過_isEncodedBlob似有方法檢查是否為轉碼字符串
  3. 如果是轉碼字符串夜畴,則再將其轉換回binary buffer數(shù)組
  4. 通過createBlob方法重建二進制文件(構造器優(yōu)先級為: Blob > BloblBuilder > MSBlobBuilder > MozBlobBuilder > WebKitBlobBuilder, 使用Builder時需通過getBlob接口s獲取指定type的Blob文件)

完整流程如下圖所示:

2. 數(shù)據(jù)庫驅動

localForage對于indexDB數(shù)據(jù)庫驅動較為復雜拖刃,主要原因為兼容多forage同時操作多個db數(shù)據(jù)庫,因而需處理復雜的數(shù)據(jù)庫upgradeneeded事件贪绘,并對每個數(shù)據(jù)庫的事務隊列進行同步化的管理兑牡,完整流程如下圖所示:

Step1 實例初始化

  1. 通過_initStorage方法創(chuàng)建forage存儲實例,該實例對應指定數(shù)據(jù)庫(name)的指定數(shù)據(jù)表(storeName)税灌,每個實例根據(jù)option的設置(name均函,version,storeName等)建立一個對應的本地記錄_dbInfo
  2. 根據(jù)這個實例的name屬性獲取對應的數(shù)據(jù)庫上下文dbContext菱涤,若未發(fā)現(xiàn)該數(shù)據(jù)庫上下文則通過createDbContext新建一個苞也,forages存儲其關聯(lián)的存儲實例,db為對應的數(shù)據(jù)庫連接(初始化為null, dbReady為事務鏈 , deferredOperations保存延時執(zhí)行的操作粘秆,除初始化和銷毀事務鏈外較少使用
  3. 獲取到數(shù)據(jù)庫上下文后如迟,根據(jù)options.version分析該數(shù)據(jù)庫的版本是否存在且最新,根據(jù)options.storeName判斷該數(shù)據(jù)庫是否存在用戶指定的數(shù)據(jù)表攻走,上述條件有一個不符合殷勘,則更新數(shù)據(jù)庫連接
  4. 之后, 通過getConnection方法獲取數(shù)據(jù)庫連接,如無需升級則直接從dbContext.db中獲取昔搂,如需升級玲销,則關閉已有連接,增加數(shù)據(jù)庫版本摘符,添加指定的數(shù)據(jù)表痒玩,觸發(fā)數(shù)據(jù)庫onupgradeneed事件淳附,在其回調中獲取數(shù)據(jù)庫連接议慰,并同步到dbContext和dbInfo中

Step2 事務處理

localForage主要使用promise鏈來管理事務蠢古,核心代碼如下:

function  _deferReadiness(dbInfo) {
  var dbContext = dbContexts[dbInfo.name];
  // Create a deferred object representing the current database operation.
  var deferredOperation = {};
  deferredOperation.promise = new  Promise(function(resolve, reject) {
    deferredOperation.resolve = resolve;
    deferredOperation.reject = reject;
  });
  // Enqueue the deferred operation.
  dbContext.deferredOperations.push(deferredOperation);
  // Chain its promise to the database readiness.
  if (!dbContext.dbReady) {`
     dbContext.dbReady = deferredOperation.promise;
  } else {
     dbContext.dbReady = dbContext.dbReady.then(function() {
       return deferredOperation.promise;
     });
  }
}

通過這部分代碼可以看到,在數(shù)據(jù)庫初始化時别凹,會建立一個事務鏈的promise對象保存到dbReady里草讶,之后所有新的事務都注冊到dbReady的then方法中,并在其resolve時替換鏈尾炉菲,實現(xiàn)循環(huán)調用堕战,這一設計十分巧妙。

與初始化時的場景類似拍霜,處理事務時也需要照顧到數(shù)據(jù)庫版本更新的問題嘱丢,同時還需要考慮到更新的數(shù)據(jù)表不在數(shù)據(jù)庫(被先前的其他實例刪掉)的異常情況,如存在問題祠饺,則同樣需觸發(fā)數(shù)據(jù)庫升級越驻,并通過tryReconnect重新建立連接,同步dbContext, dbInfo道偷,初始化事務鏈缀旁,再進行操作事務的注冊。

Step3 數(shù)據(jù)庫銷毀

所對應流程圖右下角的內容勺鸦,主要為通過indexDB.deleteDatabase方法對特定數(shù)據(jù)庫進行刪除并巍,同時通過_advanceReadiness或_rejectReadiness預先執(zhí)行事務鏈尾promise的回調(視運行時狀態(tài)而定),從而清空事務鏈换途,完成整個銷毀過程懊渡。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市军拟,隨后出現(xiàn)的幾起案子剃执,更是在濱河造成了極大的恐慌,老刑警劉巖吻谋,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忠蝗,死亡現(xiàn)場離奇詭異,居然都是意外死亡漓拾,警方通過查閱死者的電腦和手機阁最,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來骇两,“玉大人速种,你說我怎么就攤上這事〉颓В” “怎么了配阵?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵馏颂,是天一觀的道長。 經(jīng)常有香客問我棋傍,道長救拉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任瘫拣,我火速辦了婚禮亿絮,結果婚禮上,老公的妹妹穿的比我還像新娘麸拄。我一直安慰自己派昧,他們只是感情好,可當我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布拢切。 她就那樣靜靜地躺著蒂萎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪淮椰。 梳的紋絲不亂的頭發(fā)上五慈,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天,我揣著相機與錄音实苞,去河邊找鬼豺撑。 笑死,一個胖子當著我的面吹牛黔牵,可吹牛的內容都是我干的聪轿。 我是一名探鬼主播,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼猾浦,長吁一口氣:“原來是場噩夢啊……” “哼陆错!你這毒婦竟也來了?” 一聲冷哼從身側響起金赦,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤音瓷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后夹抗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绳慎,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年漠烧,在試婚紗的時候發(fā)現(xiàn)自己被綠了杏愤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡已脓,死狀恐怖珊楼,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情度液,我是刑警寧澤厕宗,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布画舌,位于F島的核電站,受9級特大地震影響已慢,放射性物質發(fā)生泄漏曲聂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一蛇受、第九天 我趴在偏房一處隱蔽的房頂上張望句葵。 院中可真熱鬧,春花似錦兢仰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至忆矛,卻和暖如春察蹲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背催训。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工洽议, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人漫拭。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親欺抗。 傳聞我的和親對象是個殘疾皇子视事,可洞房花燭夜當晚...
    茶點故事閱讀 43,576評論 2 349

推薦閱讀更多精彩內容

  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當在唯一索引所對應的列上鍵入重復值時,會觸發(fā)此異常礼旅。 O...
    我想起個好名字閱讀 5,256評論 0 9
  • 1. 簡介 1.1 什么是 MyBatis 膳叨? MyBatis 是支持定制化 SQL、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,459評論 0 4
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,092評論 1 32
  • -- 來源于網(wǎng)絡 -- 更詳細的介結參考聯(lián)機幫助文檔 xp_cmdshell--*執(zhí)行DOS各種命令痘系,結果以文本行...
    overad閱讀 2,351評論 0 13
  • 點擊查看原文 Web SDK 開發(fā)手冊 SDK 概述 網(wǎng)易云信 SDK 為 Web 應用提供一個完善的 IM 系統(tǒng)...
    layjoy閱讀 13,708評論 0 15