<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] ## 概述 隨著瀏覽器的處理能力不斷增強,越來越多的網站開始考慮,將大量數據儲存在客戶端,這樣可以減少用戶等待從服務器獲取數據的時間。 現有的瀏覽器端數據儲存方案,都不適合儲存大量數據:cookie不超過4KB,且每次請求都會發送回服務器端;Window.name屬性缺乏安全性,且沒有統一的標準;localStorage在2.5MB到10MB之間(各家瀏覽器不同)。所以,需要一種新的解決方案,這就是IndexedDB誕生的背景。 通俗地說,IndexedDB就是瀏覽器端數據庫,可以被網頁腳本程序創建和操作。它允許儲存大量數據,提供查找接口,還能建立索引。這些都是localStorage所不具備的。就數據庫類型而言,IndexedDB不屬于關系型數據庫(不支持SQL查詢語句),更接近NoSQL數據庫。 IndexedDB具有以下特點。 (1)鍵值對儲存。?IndexedDB內部采用對象倉庫(object store)存放數據。所有類型的數據都可以直接存入,包括JavaScript對象。在對象倉庫中,數據以“鍵值對”的形式保存,每一個數據都有對應的鍵名,鍵名是獨一無二的,不能有重復,否則會拋出一個錯誤。 (2)異步。?IndexedDB操作時不會鎖死瀏覽器,用戶依然可以進行其他操作,這與localStorage形成對比,后者的操作是同步的。異步設計是為了防止大量數據的讀寫,拖慢網頁的表現。 (3)支持事務。?IndexedDB支持事務(transaction),這意味著一系列操作步驟之中,只要有一步失敗,整個事務就都取消,數據庫回到事務發生之前的狀態,不存在只改寫一部分數據的情況。 (4)同域限制?IndexedDB也受到同域限制,每一個數據庫對應創建該數據庫的域名。來自不同域名的網頁,只能訪問自身域名下的數據庫,而不能訪問其他域名下的數據庫。 (5)儲存空間大?IndexedDB的儲存空間比localStorage大得多,一般來說不少于250MB。IE的儲存上限是250MB,Chrome和Opera是剩余空間的某個百分比,Firefox則沒有上限。 (6)支持二進制儲存。?IndexedDB不僅可以儲存字符串,還可以儲存二進制數據。 目前,Chrome 27+、Firefox 21+、Opera 15+和IE 10+支持這個API,但是Safari完全不支持。 下面的代碼用來檢查瀏覽器是否支持這個API。 ~~~ if("indexedDB" in window) { // 支持 } else { // 不支持 } ~~~ ## indexedDB.open方法 瀏覽器原生提供indexedDB對象,作為開發者的操作接口。indexedDB.open方法用于打開數據庫。 ~~~ var openRequest = indexedDB.open("test",1); ~~~ open方法的第一個參數是數據庫名稱,格式為字符串,不可省略;第二個參數是數據庫版本,是一個大于0的正整數(0將報錯)。上面代碼表示,打開一個名為test、版本為1的數據庫。如果該數據庫不存在,則會新建該數據庫。如果省略第二個參數,則會自動創建版本為1的該數據庫。 打開數據庫的結果是,有可能觸發4種事件。 * success:打開成功。 * error:打開失敗。 * upgradeneeded:第一次打開該數據庫,或者數據庫版本發生變化。 * blocked:上一次的數據庫連接還未關閉。 第一次打開數據庫時,會先觸發upgradeneeded事件,然后觸發success事件。 根據不同的需要,對上面4種事件設立回調函數。 ~~~ var openRequest = indexedDB.open("test",1); var db; openRequest.onupgradeneeded = function(e) { console.log("Upgrading..."); } openRequest.onsuccess = function(e) { console.log("Success!"); db = e.target.result; } openRequest.onerror = function(e) { console.log("Error"); console.dir(e); } ~~~ 上面代碼有兩個地方需要注意。首先,open方法返回的是一個對象(IDBOpenDBRequest),回調函數定義在這個對象上面。其次,回調函數接受一個事件對象event作為參數,它的target.result屬性就指向打開的IndexedDB數據庫。 ## indexedDB實例對象的方法 獲得數據庫實例以后,就可以用實例對象的方法操作數據庫。 ### createObjectStore方法 createObjectStore方法用于創建存放數據的“對象倉庫”(object store),類似于傳統關系型數據庫的表格。 ~~~ db.createObjectStore("firstOS"); ~~~ 上面代碼創建了一個名為firstOS的對象倉庫,如果該對象倉庫已經存在,就會拋出一個錯誤。為了避免出錯,需要用到下文的objectStoreNames屬性,檢查已有哪些對象倉庫。 createObjectStore方法還可以接受第二個對象參數,用來設置“對象倉庫”的屬性。 ~~~ db.createObjectStore("test", { keyPath: "email" }); db.createObjectStore("test2", { autoIncrement: true }); ~~~ 上面代碼中的keyPath屬性表示,所存入對象的email屬性用作每條記錄的鍵名(由于鍵名不能重復,所以存入之前必須保證數據的email屬性值都是不一樣的),默認值為null;autoIncrement屬性表示,是否使用自動遞增的整數作為鍵名(第一個數據為1,第二個數據為2,以此類推),默認為false。一般來說,keyPath和autoIncrement屬性只要使用一個就夠了,如果兩個同時使用,表示鍵名為遞增的整數,且對象不得缺少指定屬性。 ### objectStoreNames屬性 objectStoreNames屬性返回一個DOMStringList對象,里面包含了當前數據庫所有“對象倉庫”的名稱。可以使用DOMStringList對象的contains方法,檢查數據庫是否包含某個“對象倉庫”。 ~~~ if(!db.objectStoreNames.contains("firstOS")) { db.createObjectStore("firstOS"); } ~~~ 上面代碼先判斷某個“對象倉庫”是否存在,如果不存在就創建該對象倉庫。 ### transaction方法 transaction方法用于創建一個數據庫事務。向數據庫添加數據之前,必須先創建數據庫事務。 ~~~ var t = db.transaction(["firstOS"],"readwrite"); ~~~ transaction方法接受兩個參數:第一個參數是一個數組,里面是所涉及的對象倉庫,通常是只有一個;第二個參數是一個表示操作類型的字符串。目前,操作類型只有兩種:readonly(只讀)和readwrite(讀寫)。添加數據使用readwrite,讀取數據使用readonly。 transaction方法返回一個事務對象,該對象的objectStore方法用于獲取指定的對象倉庫。 ~~~ var t = db.transaction(["firstOS"],"readwrite"); var store = t.objectStore("firstOS"); ~~~ transaction方法有三個事件,可以用來定義回調函數。 * abort:事務中斷。 * complete:事務完成。 * error:事務出錯。 ~~~ var transaction = db.transaction(["note"], "readonly"); transaction.oncomplete = function(event) { // some code }; ~~~ 事務對象有以下方法,用于操作數據。 (1)添加數據:add方法 獲取對象倉庫以后,就可以用add方法往里面添加數據了。 ~~~ var store = t.objectStore("firstOS"); var o = {p: 123}; var request = store.add(o,1); ~~~ add方法的第一個參數是所要添加的數據,第二個參數是這條數據對應的鍵名(key),上面代碼將對象o的鍵名設為1。如果在創建數據倉庫時,對鍵名做了設置,這里也可以不指定鍵名。 add方法是異步的,有自己的success和error事件,可以對這兩個事件指定回調函數。 ~~~ var request = store.add(o,1); request.onerror = function(e) { console.log("Error",e.target.error.name); // error handler } request.onsuccess = function(e) { console.log("數據添加成功!"); } ~~~ (2)讀取數據:get方法 讀取數據使用get方法,它的參數是數據的鍵名。 ~~~ var t = db.transaction(["test"], "readonly"); var store = t.objectStore("test"); var ob = store.get(x); ~~~ get方法也是異步的,會觸發自己的success和error事件,可以對它們指定回調函數。 ~~~ var ob = store.get(x); ob.onsuccess = function(e) { // ... } ~~~ 從創建事務到讀取數據,所有操作方法也可以寫成下面這樣鏈式形式。 ~~~ db.transaction(["test"], "readonly") .objectStore("test") .get(X) .onsuccess = function(e){} ~~~ (3)更新記錄:put方法 put方法的用法與add方法相近。 ~~~ var o = { p:456 }; var request = store.put(o, 1); ~~~ (4)刪除記錄:delete方法 刪除記錄使用delete方法。 ~~~ var t = db.transaction(["people"], "readwrite"); var request = t.objectStore("people").delete(thisId); ~~~ delete方法的參數是數據的鍵名。另外,delete也是一個異步操作,可以為它指定回調函數。 (5)遍歷數據:openCursor方法 如果想要遍歷數據,就要openCursor方法,它在當前對象倉庫里面建立一個讀取光標(cursor)。 ~~~ var t = db.transaction(["test"], "readonly"); var store = t.objectStore("test"); var cursor = store.openCursor(); ~~~ openCursor方法也是異步的,有自己的success和error事件,可以對它們指定回調函數。 ~~~ cursor.onsuccess = function(e) { var res = e.target.result; if(res) { console.log("Key", res.key); console.dir("Data", res.value); res.continue(); } } ~~~ 回調函數接受一個事件對象作為參數,該對象的target.result屬性指向當前數據對象。當前數據對象的key和value分別返回鍵名和鍵值(即實際存入的數據)。continue方法將光標移到下一個數據對象,如果當前數據對象已經是最后一個數據了,則光標指向null。 openCursor方法還可以接受第二個參數,表示遍歷方向,默認值為next,其他可能的值為prev、nextunique和prevunique。后兩個值表示如果遇到重復值,會自動跳過。 ### createIndex方法 createIndex方法用于創建索引。 假定對象倉庫中的數據對象都是下面person類型的。 ~~~ var person = { name:name, email:email, created:new Date() } ~~~ 可以指定這個數據對象的某個屬性來建立索引。 ~~~ var store = db.createObjectStore("people", { autoIncrement:true }); store.createIndex("name","name", {unique:false}); store.createIndex("email","email", {unique:true}); ~~~ createIndex方法接受三個參數,第一個是索引名稱,第二個是建立索引的屬性名,第三個是參數對象,用來設置索引特性。unique表示索引所在的屬性是否有唯一值,上面代碼表示name屬性不是唯一值,email屬性是唯一值。 ### index方法 有了索引以后,就可以針對索引所在的屬性讀取數據。index方法用于從對象倉庫返回指定的索引。 ~~~ var t = db.transaction(["people"],"readonly"); var store = t.objectStore("people"); var index = store.index("name"); var request = index.get(name); ~~~ 上面代碼打開對象倉庫以后,先用index方法指定索引在name屬性上面,然后用get方法讀取某個name屬性所在的數據。如果沒有指定索引的那一行代碼,get方法只能按照鍵名讀取數據,而不能按照name屬性讀取數據。需要注意的是,這時get方法有可能取回多個數據對象,因為name屬性沒有唯一值。 另外,get是異步方法,讀取成功以后,只能在success事件的回調函數中處理數據。 ## IDBKeyRange對象 索引的有用之處,還在于可以指定讀取數據的范圍。這需要用到瀏覽器原生的IDBKeyRange對象。 IDBKeyRange對象的作用是生成一個表示范圍的Range對象。生成方法有四種: * lowerBound方法:指定范圍的下限。 * upperBound方法:指定范圍的上限。 * bound方法:指定范圍的上下限。 * only方法:指定范圍中只有一個值。 下面是一些代碼實例: ~~~ // All keys ≤ x var r1 = IDBKeyRange.upperBound(x); // All keys < x var r2 = IDBKeyRange.upperBound(x, true); // All keys ≥ y var r3 = IDBKeyRange.lowerBound(y); // All keys > y var r4 = IDBKeyRange.lowerBound(y, true); // All keys ≥ x && ≤ y var r5 = IDBKeyRange.bound(x, y); // All keys > x &&< y var r6 = IDBKeyRange.bound(x, y, true, true); // All keys > x && ≤ y var r7 = IDBKeyRange.bound(x, y, true, false); // All keys ≥ x &&< y var r8 = IDBKeyRange.bound(x, y, false, true); // The key = z var r9 = IDBKeyRange.only(z); ~~~ 前三個方法(lowerBound、upperBound和bound)默認包括端點值,可以傳入一個布爾值,修改這個屬性。 生成Range對象以后,將它作為參數輸入openCursor方法,就可以在所設定的范圍內讀取數據。 ~~~ var t = db.transaction(["people"],"readonly"); var store = t.objectStore("people"); var index = store.index("name"); var range = IDBKeyRange.bound('B', 'D'); index.openCursor(range).onsuccess = function(e) { var cursor = e.target.result; if(cursor) { console.log(cursor.key + ":"); for(var field in cursor.value) { console.log(cursor.value[field]); } cursor.continue(); } } ~~~ ## 參考鏈接 * Raymond Camden,?[Working With IndexedDB – Part 1](http://net.tutsplus.com/tutorials/javascript-ajax/working-with-indexeddb/) * Raymond Camden,?[Working With IndexedDB – Part 2](http://net.tutsplus.com/tutorials/javascript-ajax/working-with-indexeddb-part-2/) * Tiffany Brown,?[An Introduction to IndexedDB](http://dev.opera.com/articles/introduction-to-indexeddb/) * David Fahlander,?[Breaking the Borders of IndexedDB](https://hacks.mozilla.org/2014/06/breaking-the-borders-of-indexeddb/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看