JavaScript 第二十六篇 Web存儲機制
時間:2023-05-29 18:30:02 | 來源:網(wǎng)站運營
時間:2023-05-29 18:30:02 來源:網(wǎng)站運營
JavaScript 第二十六篇 Web存儲機制:Web Storage 最早是在 Web 超文本應(yīng)用技術(shù)工作組(WHAT-WG)的 Web 應(yīng)用 1.0 規(guī)范中描述的。
這個規(guī)范的最初的工作最終成為了 HTML5 的一部分。Web Storage 的目的是克服由 cookie 帶來的一些限制,當(dāng)數(shù)據(jù)需要被嚴格控制在客戶端上時,無須持續(xù)地將數(shù)據(jù)發(fā)回服務(wù)器。Web Storage 的兩個主要目標是:
- 提供一種在 cookie 之外存儲會話數(shù)據(jù)的途徑;
- 提供一種存儲大量可以跨會話存在的數(shù)據(jù)的機制。
Storage 類型
Storage 類型提供最大的存儲空間(因瀏覽器而異)來存儲名值對兒。Storage 的實例與其他對 象類似,有如下方法。
- clear(): 刪除所有值;Firefox 中沒有實現(xiàn) 。
- getItem(name):根據(jù)指定的名字 name 獲取對應(yīng)的值。
- key(index):獲得 index 位置處的值的名字。
- removeItem(name):刪除由 name 指定的名值對兒。
- setItem(name, value):為指定的 name 設(shè)置一個對應(yīng)的值。
Storage 類型只能存儲字符串。非字符串的數(shù)據(jù)在存儲之前會被轉(zhuǎn)換成字符串。
sessionStorage 對象
sessionStorage 對象存儲特定于某個會話的數(shù)據(jù),也就是該數(shù)據(jù)只保持到瀏覽器關(guān)閉。這個對象 就像會話 cookie,也會在瀏覽器關(guān)閉后消失。存儲在 sessionStorage 中的數(shù)據(jù)可以跨越頁面刷新而 存在,同時如果瀏覽器支持,瀏覽器崩潰并重啟之后依然可用(Firefox 和 WebKit 都支持,IE 則不行)。
因為 seesionStorage 對象綁定于某個服務(wù)器會話,所以當(dāng)文件在本地運行的時候是不可用的。存 儲在 sessionStorage 中的數(shù)據(jù)只能由最初給對象存儲數(shù)據(jù)的頁面訪問到,
IE8的強制寫入:
//只適用于 IE8sessionStorage.begin();sessionStorage.name = "Nicholas";sessionStorage.book = "Professional JavaScript";sessionStorage.commit();
globalStorage 對象
作為最初的 Web Storage規(guī)范的一部分,這個對象的目的是跨越會話存儲數(shù)據(jù),但有特定的訪問限制。要使用globalStorage,首先要指定哪些域可以訪問該數(shù)據(jù)??梢酝ㄟ^方括號標記使用屬性來實現(xiàn),如以下例子所示。
//保存數(shù)據(jù)globalStorage["wrox.com"].name = "Nicholas";//獲取數(shù)據(jù)var name = globalStorage["wrox.com"].name;
在這里,訪問的是針對域名
http://wrox.com 的存儲空間。globalStorage 對象不是 Storage 的實例, 而具體的 globalStorage["
http://wrox.com"]才是。這個存儲空間對于
http://wrox.com 及其所有子域都是可以 訪問的。可以像下面這樣指定子域名。
//保存數(shù)據(jù)globalStorage["www.wrox.com"].name = "Nicholas";//獲取數(shù)據(jù)var name = globalStorage["www.wrox.com"].name;
對 globalStorage 空間的訪問,是依據(jù)發(fā)起請求的頁面的域名、協(xié)議和端口來限制的。例如,如 果使用 HTTPS 協(xié)議在
http://wrox.com 中存儲了數(shù)據(jù),那么通過 HTTP 訪問的
http://wrox.com 的頁面就不能訪問 該數(shù)據(jù)。同樣,通過 80 端口訪問的頁面則無法與同一個域同樣協(xié)議但通過 8080 端口訪問的頁面共享數(shù) 據(jù)。這類似于 Ajax 請求的同源策略
如果不使用 removeItem() 或 者 delete 刪除,或者用戶未清除瀏覽器緩存,存儲在 globalStorage 屬性中的數(shù)據(jù)會一直保留在磁盤上。這讓 globalStorage 非常適合在客戶端存儲文 檔或者長期保存用戶偏好設(shè)置。
localStorage 對象
localStorage 對象在修訂過的 HTML 5 規(guī)范中作為持久保存客戶端數(shù)據(jù)的方案取代了 globalStorage。與 globalStorage 不同,不能給 localStorage 指定任何訪問規(guī)則;規(guī)則事先就 設(shè)定好了。要訪問同一個 localStorage 對象,頁面必須來自同一個域名(子域名無效),使用同一種 協(xié)議,在同一個端口上。這相當(dāng)于 globalStorage[location.host]。
由于 localStorage 是 Storage 的實例,所以可以像使用 sessionStorage 一樣來使用它。
storage 事件
Storage 對象進行任何修改,都會在文檔上觸發(fā)storage事件。當(dāng)通過屬性或setItem()方法保存數(shù)據(jù),使用 delete操作符或removeItem()刪除數(shù)據(jù),或者調(diào)用clear()方法時,都會發(fā)生該事件。這個事件的 event 對象有以下屬性。
- domain:發(fā)生變化的存儲空間的域名。
- key:設(shè)置或者刪除的鍵名。
- newValue:如果是設(shè)置值,則是新值;如果是刪除鍵,則是 null。
- oldValue:鍵被更改之前的值。
IndexedDB
web中的數(shù)據(jù)庫!
Indexed Database API,或者簡稱為 IndexedDB,是在瀏覽器中保存結(jié)構(gòu)化數(shù)據(jù)的一種數(shù)據(jù)庫。 IndexedDB 是為了替代目前已被廢棄的 Web SQL Database API(因為已廢棄,所以本書未介紹)而出現(xiàn) 的。IndexedDB 的思想是創(chuàng)建一套 API,方便保存和讀取 JavaScript 對象,同時還支持查詢及搜索。
IndexedDB 設(shè)計的操作完全是異步進行的。因此,大多數(shù)操作會以請求方式進行,但這些操作會在 后期執(zhí)行,然后如果成功則返回結(jié)果,如果失敗則返回錯誤。差不多每一次 IndexedDB 操作,都需要你 注冊 onerror 或 onsuccess 事件處理程序,以確保適當(dāng)?shù)靥幚斫Y(jié)果。
創(chuàng)建:
var indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB ||window.webkitIndexedDB;
打開或者創(chuàng)建一個IndexedDB
var request, database;request = indexedDB.open("admin");request.onerror = function(event){ alert("Something bad happened while trying to open: " + event.target.errorCode);};request.onsuccess = function(event){ database = event.target.result;};
在這兩個事件處理程序中,event.target 都指向 request 對象,因此它們可以互換使用。如果響 應(yīng)的是 onsuccess 事件處理程序,那么 event.target.result 中將有一個數(shù)據(jù)庫實例對象(IDBDatabase),這個對象會保存在 database 變量中。如果發(fā)生了錯誤,那 event.target.errorCode 中將 保存一個錯誤碼,表示問題的性質(zhì)。以下就是可能的錯誤碼(這個錯誤碼適合所有操作)。
- IDBDatabaseException.UNKNOWN_ERR(1):意外錯誤,無法歸類。
- IDBDatabaseException.NON_TRANSIENT_ERR(2):操作不合法。
- IDBDatabaseException.NOT_FOUND_ERR(3):未發(fā)現(xiàn)要操作的數(shù)據(jù)庫。
- IDBDatabaseException.CONSTRAINT_ERR(4):違反了數(shù)據(jù)庫約束。
- IDBDatabaseException.DATA_ERR(5):提供給事務(wù)的數(shù)據(jù)不能滿足要求。
- IDBDatabaseException.NOT_ALLOWED_ERR(6):操作不合法。
- IDBDatabaseException.TRANSACTION_INACTIVE_ERR(7):試圖重用已完成的事務(wù)。
- IDBDatabaseException.ABORT_ERR(8):請求中斷,未成功。
- IDBDatabaseException.READ_ONLY_ERR(9):試圖在只讀模式下寫入或修改數(shù)據(jù)。
- IDBDatabaseException.TIMEOUT_ERR(10):在有效時間內(nèi)未完成操作。
- IDBDatabaseException.QUOTA_ERR(11):磁盤空間不足。
默認情況下,IndexedDB 數(shù)據(jù)庫是沒有版本號的,最好一開始就為數(shù)據(jù)庫指定一個版本號。為此, 可以調(diào)用 setVersion()方法,傳入以字符串形式表示的版本號。同樣,調(diào)用這個方法也會返回一個請 求對象,需要你再指定事件處理程序。
if (database.version != "1.0"){ request = database.setVersion("1.0"); request.onerror = function(event){ alert("Something bad happened while trying to set version: " + event.target.errorCode); }; request.onsuccess = function(event){ alert("Database initialization complete. Database name: " + database.name + ", Version: " + database.version); };} else { alert("Database already initialized. Database name: " + database.name + ", Version: " + database.version);}
對象存儲空間
在建立了與數(shù)據(jù)庫的連接之后,下一步就是使用對象存儲空間①。如果數(shù)據(jù)庫的版本與你傳入的版 本不匹配,那可能就需要創(chuàng)建一個新的對象存儲空間。在創(chuàng)建對象存儲空間之前,必須要想清楚你想要 保存什么數(shù)據(jù)類型。
假設(shè)你要保存的用戶記錄由用戶名、密碼等組成,那么保存一條記錄的對象應(yīng)該類似如下所示:
var user = { username: "007", firstName: "James", lastNa me: "Bond", password: "foo"}; var store = db.createObjectStore("users", { keyPath: "username" });
事務(wù)
跨過創(chuàng)建對象存儲空間這一步之后,接下來的所有操作都是通過事務(wù)來完成的。在數(shù)據(jù)庫對象上調(diào) 用 transaction()方法可以創(chuàng)建事務(wù)。任何時候,只要想讀取或修改數(shù)據(jù),都要通過事務(wù)來組織所有 操作。在最簡單的情況下,可以像下面這樣創(chuàng)建事務(wù)①。
var transaction = db.transaction();
如前所述,這些事務(wù)都是以只讀方式訪問數(shù)據(jù)。要修改訪問方式,必須在創(chuàng)建事務(wù)時傳入第二個參 數(shù),這個參數(shù)表示訪問模式,用 IDBTransaction 接口定義的如下常量表示:READ_ONLY(0)表示只 讀,READ_WRITE(1)表示讀寫,VERSION_CHANGE(2)表示改變。IE10+和 Firefox 4+實現(xiàn)的是 IDBTransaction,但在 Chrome 中則叫 webkitIDBTransaction,所以使用下面的代碼可以統(tǒng)一接口:
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
var transaction = db.transaction("users", IDBTransaction.READ_WRITE);
取得了事務(wù)的索引后,使用 objectStore()方法并傳入存儲空間的名稱,就可以訪問特定的存儲 空間。然后,可以像以前一樣使用 add()和 put()方法,使用 get()可以取得值,使用 delete()可以 刪除對象,而使用 clear()則可以刪除所有對象。get()和 delete()方法都接收一個對象鍵作為參數(shù), 而所有這 5 個方法都會返回一個新的請求對象。例如:
示例:
var request = db.transaction("users").objectStore("users").get("007");request.onerror = function(event){ alert("Did not get the object!");};request.onsuccess = function(event){ var result = event.target.result; alert(result.firstName); //"James"};