javascript
JavaScript权威指南--客户端存储
客戶端存儲web應用允許使用瀏覽器提供的API實現將數據存儲在用戶電腦上。
客戶端存儲遵循“同源策略”,因此不同站點的頁面是無法讀取對于存儲的數據。而同一站點的不同的頁面之間是可以互相共享存儲數據的。
同源策略可以拿localStorage來講,如下:
打開http://www.w3school.com.cn/
打開http://www.w3school.com.cn/html5/index.asp
數據都是保存在對應的域名http://www.w3school.com.cn/下的,當域名同源的時候,是可以訪問到保存下來的數據的。
web應用可以選擇他們存儲數據的有效期:有臨時存儲的,可以讓數據保存至當前窗口關閉或瀏覽器退出;也有永久存儲,可以將數據永久地存儲在硬盤上,數年或者數月不失效。
客戶端存儲有以下幾種形式:
web存儲
先是HTML5的一個API,后來成了標準了。目前包含IE8在內的主流瀏覽器(可交互地)都實現了。包含localStorage和sessionStorage對象,這兩個對象實際上是持久化的關聯數組,是名值對的映射表,“名”和“值”都是字符串。web存儲易于使用,支持大容量(但非無限量)數據存儲同時兼容當前所有主流瀏覽器(但不兼容早期瀏覽器)
cookie
cookie是一種早期的客戶端存儲機制,期初是為征對服務器端腳本設計使用的。盡管在客戶端提供了非常繁瑣的javascript API來操作cookie,但它們難用至極,而且只適合少量的文本存儲。不僅如此,任何以cookie形式存儲的數據,不論服務器端是否需要,每一次HTTP請求都要把這些數據傳輸到服務器端。cookie目前仍然被大量的客戶端程序員使用的一個重要的原因是:所有新舊瀏覽器都支持它。但是,隨著Web Storage的普及,cookie將最終回歸到最初的形態:作為一種被服務端腳本使用的客戶存儲機制。
IE User Data
微軟在IE5之后的IE瀏覽器實現了專屬它的客戶端存儲機制-“User Data”。userData可以實現一定量的字符串數據存儲,對于IE8前的IE瀏覽器,可以將其用做是Web存儲的替代方案。
離線web應用
HTML5標準定義了一組“離線web應用”API,用于緩存web頁面以及相關資源(圖片,腳本,CSS文件等)。它的現實是將web應用整體存儲在客戶端,而不僅是存儲數據。它能夠讓web應用“安裝”在客戶端。這樣一來,哪怕網絡不可用的時候web應用依然是可用的。
web數據庫
為了能夠讓開發者像使用數據那樣操作大量的數據,很多主流瀏覽器紛紛實現在其中開始集成客戶端數據庫功能。Safari,Chrome,和Opera都內置了SQL數據庫的客戶端API。遺憾的是這類的API標準化最終以失敗而告終,并且,Firefox和IE看來不打算實現這類API。目前還有一種正在標準化的API,稱為“索引數據庫API”。調用該API返回的是一個不包含查詢術語的簡單數據庫對象。這兩種客戶端數據庫API都是異步的,都使用了事件處理機制(類似DOM事件的機制),這樣的方式多多少少都顯得復雜。
文件系統API
前面介紹過現代的瀏覽器都支持一個文件對象,用以將選擇的文件通過xmlHttPRequest上傳到服務器。與之相關的規范(草案階段)定義了一組API,用于操作一個私有的本地文件系統。該系統中,可以進行對文件的讀寫操作。目前正在標準化當中。
?
存儲、安全和隱私
web瀏覽器通常會提供“記住密碼”功能,這些密碼會以加密的形式安全地存儲在硬盤上。然而本章介紹的任何形式客戶端數據存儲都不牽扯加密:任何存儲在用戶硬盤上的數據都是未加密形式。這樣一來,對于擁有電腦訪問權限的惡意用戶或者惡意軟件同樣也可以獲得存儲的數據。因此,任何形式的客戶端存儲都不應該用來保存密碼、商業賬號或者類似的敏感信息。
? ? ? 還要記住一點:很多web用戶不信任那些使用cookie和其它客戶端存儲機制來做類似“跟蹤”功能的網站。所以,盡量嘗試本章討論的存儲機制來網站升級用戶體驗;而不是用它們來收集和侵犯隱私相關的數據。如果網站濫用客戶端存儲,用戶將禁用該功能。這樣一來不僅達不到效果,還會導致依賴客戶端存儲的網站完全不可用。
1.localStorage和sessionStorage
? ? ? 實現了“web存儲”草案標準的瀏覽器在window對象上定義了兩個屬性,localStorage和sessionStorage。在控制臺輸入window.localStrage可以獲得頁面所存儲的數據。
? ? ? 這兩個屬性代表同一個Storage對象——一個持久化關聯數組,數組使用字符串來索引,存儲的值也是字符串形式的,Storage對象在使用上和一般的Javascript沒有什么兩樣,設置對象的屬性為字符串值,隨后瀏覽器會將值存儲起來。lcoalStorage和sessionStorage兩者的區別在于存儲的有效期和作用域不同:數據可以存儲多長時間及擁有數據的訪問權。
示例:localStorage和sessionStorage類似
var name = localStorage.username; //查詢一個存儲的值 name = localStorage["username"]; //等于數組表示法 if (!name) { name = prompt("請輸入你的名字"); //詢問用戶一個答案localStorage.username = name; //存儲用戶的答案 } //迭代所有存儲的name/value對 for (var name in localStorage) { //迭代所有存儲的名字var value = localStorage[name]; //查詢每個名字對應的值 }Storage對象還定義了一些諸如存儲、獲取、遍歷和刪除的方法。
“web存儲”草案標準指出,我們既可以存儲結構化的數據(對象和數組),也可以存儲原始類型數據,還可以存儲諸如日期、正則表達式甚至是文件對象在內的內置類型和數據。(在一些瀏覽器中,僅僅支持存儲字符串類型數據,如果要存儲和其它類型的書,不得不自己手動進行和編碼解碼),如下例子所示:
//當存儲一個數字的時候,會自動轉換成一個字符串 //但是,當獲取該值的時候,別忘了手動轉換成數字類型 localStorage.x = 10; var x = parseInt(localStorage.x); //同樣,存儲一個日期類型數據的時候進行編碼,獲取的時候進行解碼 localStorage.lastRead = (new Date()).toUTCString(); var lastdate = new Date(Date.parse(localStorage.lastRead)); //使用JSON可以使得對基本數據類型的編碼規則變得很方法 var data = new Date(); localStorage.data = JSON.stringify(data)//編碼后存儲 var data = JSON.parse(localStorage.data)//獲取數值后再解碼1.1.存儲有效期和作用域
通過localStorage存儲的數據是永久性的,除非web應用立刻刪除存儲的數據?;蛘哂脩敉ㄟ^設置瀏覽器配置(瀏覽器提供的特定UI)來刪除,否則數據將一直保留在用戶電腦上,永不過期。
localStorage的作用域是限定在文檔源(document origin)級別的。文檔源是通過協議、主機名及端口三者來確定的。因此,每個url都有不同的文檔源。
同源文檔間共享localStorage數據(不論該源的腳本是否真正的訪問的localStorage)。它們可以互相讀取對方的數據,甚至可以覆蓋對方的數據。但是,非同源的文檔見互相都不能讀取和共享或覆蓋對方的數據(即使它們的腳本來自同一臺第三方服務器也不行)。
需要注意的是localStorage的作用域也收到瀏覽器供應商的限制。如果你使用的Firefox訪問站點那么下一次用另外一個瀏覽器打開的時候,那么本次是無法獲取上次的數據的。
?
sessionStorage的有效期和存儲數據的腳本所在最頂層的窗口或者是瀏覽器標簽頁是一樣的。一旦窗口或者標簽頁被永久關閉了,那么所有通過sessionStorage存儲的數據也被刪除了(需要注意的是,現代的瀏覽器具備了一些關閉標簽頁隨后恢復上一次瀏覽器回話的功能,可能預知相關的sessionStorage會更長些)。
作用域也是限定在文檔源中,因此,非同源的文檔之間是無法貢獻sessionStorage的。不僅如此,sessionStorage的作用域還被限定在窗口中。如果同源的文檔渲染在不同的瀏覽器標簽頁中,那么他們互相之間擁有的是各自的sessionStorage數據,無法共享。就是說,同個瀏覽器下兩個相同的標簽頁也不能共享數據。
需要注意的是:這里提到的基于窗口作用域的sessionStorage指的窗口是頂級窗口。如果一個瀏覽器標簽包含兩個<iframe>元素,它們是同源的,那么兩者之間是可以共享的sessionStorage的。
1.2.存儲API
localStorage和sessionStorage通常是被當做普通的javascript對象使用。通過設置屬性來存儲字符串值,查詢該屬性來讀取該值。這兩個對象還提供了兩個正式的API。
setItem()getItem()removeItem()(在非IE8的瀏覽器中,還可以使用delete操作符來刪除數據,就和普通對象使用的delete操作符一樣)clear()(不需要參數)使用length和key()方法,傳入0~length~1的數字,可以枚舉所有存儲數據的名字。示例:
localStorage.setItem("x", 1); //以"x"的名字存儲一個數值 localStorage.getItem("x"); //獲取x的數值 //枚舉所有的存儲的名字/值對 for(var i = 0;i<localStorage.length;i++){//length 表示了所有名字/值對 var name = localStorage.key(i); //獲取第i對的名字 var value = localStorage.getItem(name);//獲取該對的值 } localStorage.removeItem("x")//刪除"x"項 localStorage.clear();//全部刪除如果瀏覽器提供商完全實現了“web存儲”的標準,只對對象和數組類型的數據存儲,那么就會又多了一個使用類似用setItem()和getItem()這類方法的理由。對象和數組的值通常是可變的,因此存儲對象要求存儲它們的副本,以確保之后對任何這類對象的改變不影響到存儲的對象。同樣的 ,在獲取該對象的時候,也要求獲取是該對象的副本,以確保已獲取的對象的改動不會影響到存儲的對象。而這類操作如果如果使用基于屬性的API就會令人困惑。考慮如下這段代碼(假設瀏覽器已經支持了結構化數據存儲)。
localStorage.o = {x:1};//存儲一個帶有"x"屬性的對象 localStorage.o.x = 2; //試圖設置該對象的屬性值 localStorage.o.x; //=>undefined x沒有改變......
目前還沒完全實現這個標準呢。
1.3、存儲事件
無論什么時候,存儲在localStorage或者sessionStorage的數據發生改變,瀏覽器都會在其它對該數據可見的窗口對象上出發存儲事件(但是在對數據改變的窗口上是不出發的)。如果瀏覽器有兩個標簽頁都打開了來自于同源的頁面,其中一個在localStorage上存儲了數據,那么在另外一個標簽頁就會接受到一個存儲事件。要記住,sessionStorage的作用域是限制在頂層窗口的,因此對于sessionStorage的改變只有相關牽連的窗口才會觸發存儲事件。像給已經存在的存儲項設置一個一模一樣的值,或者是刪除一個本來就不存在的項存儲都是不會觸發存儲事件的。
為存儲事件注冊處理程序可以通過addEventListener()方法,(或者在IE下使用attachEvent方法)。在絕大多瀏覽器中,還可以給Window對象設置onstorage屬性的方法,不過Firefox不支持該屬性。
與事件相關的事件對象有5個非常重要的屬性(遺憾的是IE8不支持他們)
key:被設置或移除項的鍵名。如果調用clear()函數,那么該屬性值就為null.
newValue:保存該項新值;或者調用removeItem()時,該屬性值為null。
oldvalue:改變或刪除該項前,保存該項的原先值;當插入一個新項的時候,該屬性值為null
storageArea:這個屬性值就好比目標window對象上的locaStorage屬性或者是sessionStorgae屬性
url:觸發該存儲變化腳本所在的文檔URL
最后,要注意的是:localStorage和sessionStorage存儲機制都是廣播機制的,瀏覽器會對目前正在訪問的同源站點所有窗口發送消息。舉個例子:如果一個用戶要求網站停止動畫效果時,那么該站點可能會在localStorage中存儲該用戶的首選項,這樣依賴,以后再訪問該站點的時候自動停止該動畫效果了。因為存儲了首選項,導致觸發的一個存儲事件讓其它的同源頁面也獲得了一個用戶請求。再比如,一個機遇web的圖片編輯應用,通常允許在其它窗口中展現工具條。當用戶選擇一個工具的時候,應用就可以使用localStorage來存儲用戶的當前狀態,然后通知其它的窗口用戶選擇了新的工具。
?
2.cookies
cookie是指web瀏覽器存儲少量的數據,同時它是與具體的web頁面或者站點相關的。cookie是最早是設計為被服務端所有的,從底層來看,作為HTTP協議的一種擴展實現它。cookie數據會自動在web瀏覽器和web服務器之間傳輸的,因此服務端腳本就可以讀、寫客戶端的cookie值。?
可以通過document.cookie來獲取cookie值。
為什么叫“cookie”?
并沒太多含義。在javascript中,cookie用于保存狀態以及能夠為web瀏覽器提供一種身份識別(密碼等)。但是,javascript中使用cookie不會采取任何加密機制,因此是不安全的。(但是通過https傳說cookie數據是安全的,不過這和cookie本身無關,而和https:協議相關)。
操作cookie的api很早就已經定義和實現了,因此該API的兼容性很好。但是,該API幾乎形同虛設。根本沒有提供諸如查詢、設置、刪除cookie對象的方法,所有這些操作都要通過特殊格式的字符串形式讀寫Document對象的cookie屬性來完成。每個cookie的有效期和作用域都可以通過cookie屬性分別指定。這些屬性也是通過在同一個cookie上以特殊的字符串來設定的。
檢測cookie是否可用
由于濫用第三方cookie(如cookie是和網頁上的圖片相關而非網頁本身相關。第三方cookie指的是來自于當前訪問站點以為的站點設置的cookie)的緣故,導致cookie在大多數web用戶心中有不好的印象。比如,廣告公司可以利用第三方cookie來實現跟蹤用戶的訪問行為和習慣,而用戶為了禁止這種“窺探”用戶隱私的行為會在它們的瀏覽器中禁用cookie。因此在使用avascript操作cookie前,首先要確保cookie是啟用的。在絕大多數瀏覽器中,可用通檢測過navigator.cookieEnabled這個屬性來實現,若為true則表明cookie是啟用的。因為該屬性不是一個標準的屬性,所以在不支持該屬性的瀏覽器上,要用下面介紹的cookie技術來讀、寫和刪除cookie數據來測試是否支持cookie。
2.1.cookie屬性:有效期和作用域
除了名(name)和值(value),cookie還有一些可選的屬性來控制cookie的有效期和作用域。cookie的默認有效期很短暫;它只在持續在web會話期間,一旦關閉瀏覽器,cookie的保存數據就丟失。需要注意的是這與sessionStorage有效期還是有區別的,cookie的作用域并不是限在瀏覽器的單個窗口中,它的有效期和整個瀏覽器進程不是單個瀏覽器窗口的有效期一一致。如果要延長cookie有效期,可以通過設置max-age屬性,但必須要明確告訴cookie的有效期是多長,單位是秒。
一旦設置了有效期,瀏覽器就會將cookie數據存儲在一個文件中,并且知道過了指定的有效期才會刪除該文件。
和localStorage以及sessionStorage類似,cookie的作用域是通過文檔源和文檔路徑來確定的。該作用域通過cookie的path和domain屬性配置的。在默認的情況下,cookie和創建它的web頁面有關,并對該web頁面及和該web頁面同目錄或者子目錄其它的頁面可見。比如web頁面http://www.a.com/a/index.html頁面創建了一個cookie,那么該cookie對http://www.a.com/a/b.html和頁面http://www.a.com/a/b/index.html頁面都是可見的。但對http://www.a.com/c.html是不可見的。
默認的cookie的可見性行為滿足了最常見的需求。不過,有的時候,你可能希望整個網站都使用cookie的值,而不管是那個頁面創建它的。比如用戶在一個頁面表單上輸入了它的郵件地址,你想把它保存下來,為了不讓用戶下次回到這個頁面上將其作為默認的郵件地址。要滿足這樣的需求,可以設置cookie的路徑(設置cookie的path屬性)。
將cookie的路徑設置成"/"等于是讓cookie和localStorage擁有同樣的作用域,同時當它請求該站點上任何一個web頁面的時候,瀏覽器都必須將cookie的名字和值傳遞給服務器。但是需要注意的是,cookie的path屬性不能被用做訪問控制機制。如果一個web頁面想要讀取同一站點其它頁面的cookie,只需要將其他頁面隱藏<iframe>形式加載進來,隨后讀取對應文檔的cookie就可以了。同源策略限制了跨站的cookie窺探,但是對同一站點的文檔是完全合法的。
cookie的作用域默認由文檔源限制。但是,有的大型網站想要子域之間能夠相互通信cookie,這個時候就需要設置coolkie的domian屬性來達到目的。如果http://well.a.com的域下創建了一個cookie,并將其path屬性設置成"/",其domian屬性設置成".a.com",那么這個cookie就對所有good.a.com,other.a.com以及任何其它a.com域下任何其它服務器都可見。如果沒有為一個cookie設置域屬性,那么domian屬性的默認值是當前web服務器的主機名。要注意的是,cookie域只能設置當前服務器的域。
最后要介紹的cookie的屬性是secure,它是一個布爾值屬性,用來表明cookie的值是以何種網絡傳輸。cookie默認是以不安全的形式(通過普通的、不安全的HTTP連接)傳遞的。一旦cookie被標識為“安全的”,那就只能當前瀏覽器和服務器通過https或者其它安全協議連接的時候才能傳遞它。
2.2.保存cookie
要給當前文檔設置有效的cookie值,非常簡單,只需將cookie屬性設置為一個字符串的形式的值;
name = value;如下:
document.cookie = "version=" + encodeURIComponent(document.lastModified);下次讀取cookie屬性的時候,之前存儲的名/值對的數據就在cookie列表中。由于cookie的名/值中不允許包含分號、逗號和空白符,因此,在存儲之前一般可以采用javascript核心的全局函數encodeURIComponent()進行編碼。相應的,讀取cookie值的時候需要采用decodeURICompoent()函數解碼。
以簡單的名/值對形式存儲的cookie數據有效期只在當前的web瀏覽器會話內,一但用戶關閉瀏覽器,cookie數據就丟失了。如果小要延長cookie的有效期,就需要設置max-age屬性來指定cookie的有效期(單位是秒)。按照下面的字符串形式設置cookie的屬性即可。
name = value; max-age = seconds下面設置一個cookie值,并提供一個max-age屬性
//以名/值對形式存儲cookie //同時采用encodeURIComponet()函數進行編碼,來轉義分號、逗號和空白符 //如果dayTolive是一個數字,設置max-age屬性為該數值表示cookie知道指定的天數 //到了才會過期。如果daysTolive是0就表示刪除cookie function setcookie(name, value, daysTolive) {var cookie = name + "=" + encodeURIComponent(value);if (typeof daysTolive === "number")cookie += "; max-age =" + (daysTolive * 60 * 60 * 24);document.cookie = cookie; } setcookie("cook","cool",0);同樣地,如果要設置cookie的path、domian和secure屬性,只需如下的字符串追加在cookie的值的后面
;path = path ;domain = domian ;secure要改變cookie的值,需要使用相同的名字、路徑和域,但是新的值重新設置cookie的值。同樣地,設置新max-age屬性就可以改變cookie的有效期。
要刪除一個cookie,需要使用相同的名字、路徑和域,然后制定一個任意(非空)的值,并將max-age屬性指定為0,再次設置cookie。
2.3.讀取cookie
使用javascript表達式來讀取cookie屬性的時候,其返回的值是一個字符串,該字符串都是由一系列的名/值對組成,不同名/值對之間通過“分號/空格”分開,其內容包含了所有作用在當前文檔的cookie。但是當它不包含其它設置的cookie屬性。通過document.cookie屬性可以獲取cookie的值,但是為了更好地查看cookie值,一般會采用split()的方法將cookie值中的名/值對都分離出來。
把cookie的值從cookie屬性分離出來之后,必須要采用相應的解碼方式(取決于之前存儲cookie值時的采用的編碼方式),把值還原出來。比如,先采用decodeURIComponent()方法把cookie的值解碼出來,之后再利用JSON.parse()方法轉換成json對象。
下面的例子定義了一個getcookie()函數,該函數將document.cookie屬性的值解析出來,將對應的名/值存儲到一個對象中,函數最后返回該對象。
/**解析document.cookie屬性的值**/ //將document.cookie的值以名/值對組成一個對象返回 //假設存儲cookie的值的時候是采用encodeURIComponent()編碼的 function getcookie() {var cookie = {}; //初始化要返回的對象var all = document.cookie; //在一個大寫的字符串中獲取所有的cookie值if (all === "") //如果cookie為空字符串return cookie; //返回一個空對象var list = all.split(";"); //分離出名/值對for (var i = 0; i < list.length; i++) { //遍歷每個cookievar cookie = list[i];var p = cookie.indexOf("="); //查找第一個"="符號var name = cookie.substring(0, p); //獲取cookie名字var value = cookie.substring(p + 1); //獲取cookie對應的值value = decodeURIComponent(value); //對其值進行解碼cookie[name] = value; //將名/值對存儲到對象中 }return cookie; }在wamp下測試,不能用,結果都會直接等于list而不是對象。cookie不能直接用啦,修改如下:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Document</title> </head> <body><script type="text/javascript">function setcookie(name, value, daysTolive) {var cookie = name + "=" + encodeURIComponent(value);if (typeof daysTolive === "number")cookie += "; max-age =" + (daysTolive * 60 * 60 * 24);document.cookie = cookie;}setcookie("cook","cool",60);function getcookie() {var cookie = {}; //初始化要返回的對象var all = document.cookie; //在一個大寫的字符串中獲取所有的cookie值if (all === "") //如果cookie為空字符串return cookie; //返回一個空對象var list = all.split(";"); //分離出名/值對for (var i = 0; i < list.length; i++) { //遍歷每個cookievar cookieEle = list[i];var p = cookieEle.indexOf("="); //查找第一個"="符號var name = cookieEle.substring(0, p); //獲取cookie名字var value = cookieEle.substring(p + 1); //獲取cookie對應的值value = decodeURIComponent(value); //對其值進行解碼cookie[name] = value; //將名/值對存儲到對象中 }return cookie;}console.log(getcookie());</script> </body> </html>2.4.cookie的局限性
cookie的設計初衷是給服務端腳本用來存儲少量的數據的,該數據會在每次請求一個相關的URL時傳遞到服務器中。RFC2965鼓勵瀏覽器供應商對cookie的數據大小不做限制??墒?#xff0c;要知道,該標準不允許瀏覽器保存超過300個cookie,為每個web服務器保存的cookie數不能超過20個(是對整個服務器而言,而不僅僅指服務器上的頁面和站點),而且,每個cookie保存的數據不能超過4k。實際上,現代瀏覽器允許cookie總數超過300個,但是部分瀏覽器對單個cookie大小仍然有4k的限制。
2.5.cookie相關存儲
例:定義一個cookieStorage函數,通過將max-age和path屬性傳遞給該構造函數,通過將max-age和path屬性傳遞給該構造函數,就會返回一個對象,然后就可以像使用localStorage屬性或sessionStorage一樣來使用這個對象。但是要注意的是,該例并沒有實現存儲事件,因此,當設置和查詢cookieStorage對象的屬性的時候,不會實現自動保存和獲取對應的值。
實現基于cookie的API。
?
3.利用IE userdata持久化數據
IE以及IE5以上的瀏覽器是通過在document元素后附件一個專屬的"DHTML行為"來實現客戶端存儲的。如下代碼所示:
var memory = document.createElement("div"); //創建一個元素 memory.id = "_memory"; memory.style.display = "none"; memory.style.behavior = "url('default#userData')"; //附加userData行為 document.body.appendChild(memory); //添加到document元素中一旦元素賦予了"userData"行為,該元素就擁有load()和save()方法。load()方法用于載入存儲的數據。使用它的時候必須傳遞一個字符串作為參數--類似一個文件名,該參數用來指定要載入的存儲數據。當數據載入后,就可以通過該元素的屬性來訪問這些名/值對形式的數據,可以使用gettAttribute()來查詢攝像數據。通過setAttribute()方法設置屬性。然后調用save()方法可以存儲新的數據;而要刪除數據,通過使用removeAttribute()方法然后調用save()方法即可。如下所示(該例使用了此前例子中初始化的那個memory元素):
memory.load("mySoredData"); //根據指定名,載入對于的數據 var name = memory.getAttribute("username"); //獲取其中數據片段 if (!name) { //如果沒有指定的數據片段name = prompt("請輸入"); // memory.setAttribute("username", name); //將其設置成memory元素的一個屬性memory.save("mySoredData") }默認情況下,通過userData存儲的數據,除非手動去刪除它否則永不失效。但是,也可以通過設置expires屬性來指定它的過期時間。就拿上面的例子來說,可以給存儲的數據設置時長為100天的有效期,如下所示:
var now = (new.Date()).getTime(); //獲取當前時間,以毫秒為單位 var expires = now + 100 * 24 * 60 * 60 * 1000; //100天的毫秒算法 expires = new Date(expires).toUTCString(); //將其轉換為字符串。 memory.expires = expires; //設置userData的過期時間IE userData的作用域限制在和當前文檔同目錄的文檔中。它的作用域沒有cookie寬泛,cookie對其所在目錄下的子目錄也有效。userData的機制并沒有像cookie那樣,通過設置path和domain屬性來控制或改變其作用域的方式。
userData允許存儲的數據量要比cookie大,但是卻比localStorage和sessionStorage允許的存儲量的數據量要小。
下面的例子基于IE的userData實現存儲了API提供的getItem(),setItem()以及removeItem()方法(但是它沒有實現key()或者clear()方法,原因是userData并沒有定義遍歷所有存儲項的一種方法)。
。。。。。。
由于上述代碼只在IE瀏覽器下有效,最好使用IE條件注釋來避免其他瀏覽器載入上述代碼。
<!--[if IE]> <script src="userDataStorage.js"></script> <![endif]-->?4.應用程序存儲和離線Web應用
HTML5中新增了“應用程序緩存”,允許web應用程序自身本地保存到用戶的瀏覽器中。不像localStorage和sessionStorage只是保存web應用程序相關的數據,它是將應用程序自身保存起來----應用程序所需運行的所有文件(HTML、CSS、JavaScript、圖片等)?!皯贸绦蚓彺妗焙鸵话愕臑g覽器緩存不同:它不會隨著用戶清除瀏覽器緩存而被清除。同時,緩存起來的應用程序也不會像一般固定大小的緩存那樣,老數據會被最近一次訪問的新數據代替掉。它其實不是臨時存儲在緩存中:應用程序更像是被“安裝”在那里,除非被用戶“卸載”或“刪除”它們,否則,它們就會一直“駐扎”在那里。所以說,“應用程序緩存”在真正意義上不是“緩存”更好的說法應該稱之為“應用程序存儲”。
讓web應用能夠實現“本地安裝”的目的是要保證它們能夠在離線狀態(比如,當在飛機或者手機沒信號的時候)下依然可訪問。將自己“安裝”到應用程序緩存中的Web應用,在離線狀態下使用localStorage來保存應用相關的數據,同時還具備一套同步機制,在再次回到在線狀態的時候,能夠將存儲的數據傳輸給服務器。
4.1.應用程序緩存清單
想要將應用程序“安裝”到應用程序緩存中,首先要創建一個清單:包含所有應用程序依賴的所有url列表。然后,通過在應用程序主HTML頁面的<html>標簽中設置manifest屬性,指向到清單文件就可以了:
<!DOCTYPE HTML><html manifest=”myapp.appcache”><head>…</head><body>…</body></html>清單文件中的首行內容必須以”CACHE MANIFEST”字符串開始。其余就是要緩存的文件URL列表,一行一個URL。相對路徑的URL都相對于清單文件的URL? 。會忽略內容中的空行,會作為注釋而忽略以”#”開始的行。注釋前面可以有空格,但同在同一行注釋后面是不允許有非空字符串的。
比如:
CACHE MANIFEST #上面一行標識此文件是一個清單文件。本行是注釋 # 下面的內容都是應用程序依賴的資源文件的URL myapp.html myapp.js myapp.css images/background.png補充:
緩存清單的MIME類型: 應用程序緩存清單文件約定以.appcache作為文件擴展名。但是,這也僅僅只是約定而已,web服務器真正識別清單文件的方式是通過”text/cache-manifest”這個MIME類型的一個清單。如果服務器將清單文件的Content-Type的頭信息設置成其他MIME類型,那么就不會緩存應用程序了。因此,可能需要對web服務器做一定的配置來使用這個MIME類型,比如,在Web應用目錄下創建Apache服務器的一個.htaccess文件清單文件包含要緩存的應用的標識。如果一個Web應用有很多web頁面,那么每個html頁面就需要設置<html manifest=>屬性來指向清單文件。事實上,將這些不同的頁面都指向同一個清單文件,可能很清楚地表達出它們都是需要緩存起來的,同時它們又是來自同一個web應用的。如果一個應用只有少量的html頁面,那么一般會把這些頁面都顯示地列在清單文件中。但這不是強調的,會認為任何鏈接到清單文件的文件都是web應用的一部分,并會隨著應用一起緩存起來。
像之前提到的,一個簡單的清單必須列出web應用依賴的所有資源。一旦一個Web應用首次下載下來并緩存,之后的任何加載請求都來自緩存。從緩存中去載入一個應用資源的時候,就要求它請求的資源務必要在清單中。不會載入不在清單的資源。這種政策有點離線的味道。如果一個簡單的緩存起來的應用能夠從緩存中載入并運行,那么它也可以在瀏覽器的離線狀態下運行。通常情況下,很多復雜的web應用無法將它們依賴的所有資源都緩存起來。但是,如果它們同時也有一個復雜的清單的話,它們仍然可能使用應用程序緩存。
復雜的清單
清單文件還有比這更復雜的語法,列舉資源的方式也還有另外兩種。在清單文件中可以使用特殊的區域頭(譯者注:類似于HTTP頭)來標識該頭信息之后清單項的類型。像該例中列舉的簡單緩存項事實上都屬于“CACHE:”區域,這也是默認的區域。另外兩種區域是以“Network:”和”FALLBACK:” 頭信息開始的(一個清單文件可以有任意數量的區域,而且可以相鄰兩個區域之間可以根據需要相互切換)。
“NETWORK:”區域標識了該區域中的資源從不緩存,總要通過網絡獲取。通常,會將一些服務端的腳本資源放在”NETWORK:”區域中,而一般該區域中的資源的URL都只是URL前綴,用來表示以此URL前綴開頭的資源都應該要通過網絡加載?!盢ETWORK:”區域中的URL還支持”*”通配符。該通配符表示對任何不在清單中的資源,瀏覽器都將通過網絡去獲取。這實際上違背了這樣一條規則:緩存應用程序必須要在清單中列舉所有應用相關的資源!
“FALLBACK:”區域中的清單項每行都包含兩個URL。第二個URL是指需要緩存起來的資源,第一個URL是一個前綴。任何能夠匹配到該前綴的資源都不會緩存起來,但是可能的話,他們會從網絡中載入。如果從網絡中載入失敗的話,會使用第二個URL指定的資源來代替,從緩存中獲取。想象一個應用包含了一定數量的視頻教程。這些視頻都很大,顯然把他們緩存到本地是不合適的。因此,在離線狀態下,通過清單文件中的fallback區域,就可以使用一些文本類的幫助文檔來代替了。
示例
CACHE MANIFESTCACHE: myapp.html myapp.css myapp.jsFALLBACK: videos/ offline_help.htmlNETWORK: cgi/4.2.緩存的更新
當一個web應用從緩存中載入的時候,所有與之相關的文件也是直接從緩存中獲取。在線狀態下,瀏覽器會異步檢查是否清單文件有更新。如果有更新,新的清單文件以及所有清單中列舉的文件都會下載下來重新保存到應用程序緩存中。但是,要注意的是,瀏覽器只是檢查清單文件,而不會去檢查緩存的文件是否有更新:只檢查清單文件。比方說,你修改了一個緩存的JavaScript文件,要想讓該文件生效,就必須去更新下清單文件。由于應用程序依賴的文件列表其實并沒有變化,因此最簡單的方式就是更新版本號:
CACHE MANIFEST # MyApp version 1 (更改這個數字以便讓瀏覽器重新下載這個文件) MyApp.html MyApp.js同樣的,如果想要讓web應用從緩存中“卸載”,要在服務器端刪除清單文件,使得請求該文件的時候返回HTTP 404 無法找到 的錯誤,同時,修改HTML文件與該清單列表“斷開鏈接”。
要注意的是,瀏覽器檢查清單文件以及更新緩存的操作是異步的,可能是在從緩存中載入應用之前,也有可能同時進行。因此,對于簡單的web應用而言,在你更新清單文件之后,用戶必須載入應用兩次才能保證最新的版本生效:第一次是從緩存中載入老版本隨后更新緩存,第二次才從緩存中載入最新的版本。
瀏覽器在更新緩存過程中會觸發一系列事件,你可以通過注冊處理程序來跟蹤這個過程同時提供反饋給用戶。?
......
4.3.離線web應用
離線web應用指的是將自己“安裝”在應用程序緩存中的程序,使得哪怕在瀏覽器處于離線狀態時候依然可訪問。舉個最簡單的例子——類似時鐘和萬花筒生成器這樣的應用——這是web應用要離線可用需要做的事情。但是,大多數web用也需要向服務器上傳數據:哪怕是簡單的游戲應用都有可能需要上傳用戶的最高得分到服務器。這類應用也可以成為離線應用。他們可以使用localStorage來存儲應用數據,然后當在線的時候再將數據上傳到服務器。在本地存儲和服務器端同步數據是將Web應用轉變為離線應用最巧妙的環節,特別是當用戶需要從多臺設備獲取數據的時候。
為了在離線狀態可用,web應用需要可以告知別人自己是離線還是在線,同時當網絡連接的狀態發生改變時候也能“感知”到。通過navigator.onLine屬性,可以檢測瀏覽器是否在線,同時,在Window對象上注冊在線和離線事件處理程序,可以檢測網絡連接狀態的改變。
一個簡單的記事本程序
?
20170420補充
瀏覽器對于存儲數據的大小有限制,限制的大小普遍在5M/域,超出則會報Uncaught QuotaExceededError錯誤。因此在開發時應注意控制存儲數據保持在限制大小內,并定時清除無用的數據。若要手動刪除數據,Chrome瀏覽器可至chrome://settings/cookies 查看不同網站已使用本地存儲的占用空間情況,并進行刪除操作。
?
轉載于:https://www.cnblogs.com/Chen-XiaoJun/p/6437741.html
總結
以上是生活随笔為你收集整理的JavaScript权威指南--客户端存储的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 207. 课程表/210. 课程表 II
- 下一篇: Qt中对main.cpp的代码解释