第23 离线应用与客户端存储
1. 离线检测
(1)
navigator.onLine 属性
,这个属性值为true表示设备能上网,值为false表示设备离线。
(2)两个事件: online 和 offline。
当网络从离线变为在线或者从在线变为离线时,分别触发这两个事件。这两个事 件在 window 对象上触发。
2. 应用缓存
(1) HTML5 的
应用缓存(application cache)
,或者简称为 appcache,是专门为开发离线 Web 应用而设计 的。Appcache 就是从浏览器的缓存中分出来的一块缓存区。要想在这个缓存中保存数据,可以使用一个描述文件(manifest file)
,列出要下载和缓存的资源。
(2) 要将描述文件与页面关联起来,可以在<html>中的 manifest 属性中指定这个文件的路径<htmlmanifest="/offline.manifest">
这个文件的 MIME 类型必须是 text/cache-manifest1。
(3)applicationCache 对象
,这个对象有一个status 属性
,属性的值是常量,表示应用缓存的如下当前状态。
- 0:无缓存,即没有与页面相关的应用缓存。
- 1:闲置,即应用缓存未得到更新。
- 2:检查中,即正在下载描述文件并检查更新。
- 3:下载中,即应用缓存正在下载描述文件中指定的资源。
- 4:更新完成,即应用缓存已经更新了资源,而且所有资源都已下载完毕,可以通过 swapCache()来使用了。
- 5:废弃,即应用缓存的描述文件已经不存在了,因此页面无法再访问应用缓存。
(4) 应用缓存还有很多相关的事件,表示其状态的改变。以下是这些事件。
- checking:在浏览器为应用缓存查找更新时触发。
- error:在检查更新或下载资源期间发生错误时触发。
- noupdate:在检查描述文件发现文件无变化时触发。
- downloading:在开始下载应用缓存资源时触发。
- progress:在文件下载应用缓存的过程中持续不断地触发。
- updateready:在页面新的应用缓存下载完毕且可以通过 swapCache()使用时触发。
- cached:在应用缓存完整可用时触发
(5)
update()方法
也可以 手工干预,让应用缓存为检查更新而触发上述事件。applicationCache.update();
(6) 如果触发了updateready 事件
,则说明新版本的应用缓存已经可用,而此时你需 要调用swapCache()来启用新应用缓存
。
EventUtil.addHandler(applicationCache, "updateready", function(){
applicationCache.swapCache();
});
3. 数据存储
(1) Cookie
HTTP Cookie
,通常直接叫做 cookie,最初是在客户端用于存储会话信息的。该标准要求服务器对任意 HTTP 请求发送Set-Cookie
HTTP 头作为响应的一部分,其中包含会话信息。- 浏览器会存储这样的会话信息,并在这之后,通过为每个请求添加
Cookie HTTP 头
将信 息发送回服务器。
* 限制
cookie 在性质上是绑定在
特定的域名下
的。当设定了一个 cookie 后,再给创建它的域名发送请求时, 都会包含这个 cookie。这个限制确保了储存在 cookie 中的信息只能让批准的接受者访问,而无法被其他 域访问。
- 每个域的 cookie 总数是有限的,不过浏览器之间各有不同。
- 浏览器中对于 cookie 的尺寸也有限制。大多数浏览器都有大约 4096B(加减 1)的长度限制。
*cookie 的构成
cookie 由浏览器保存的以下几块信息构成:
- 名称(name):一个唯一确定 cookie 的名称。cookie 名称是不区分大小写的,所以 myCookie 和 MyCookie 被认为是同一个 cookie。然而,实践中最好将 cookie 名称看作是区分大小写的,因为某些服务器会这样处理 cookie。cookie 的名称必须是经过 URL 编码的。
- 值:储存在 cookie 中的字符串值。值必须被 URL 编码。
- 域(domain):cookie 对于哪个域是有效的。所有向该域发送的请求中都会包含这个 cookie 信息。这个值
可以包含子域(subdomain,如 www.wrox.com),也可以不包含它(如.wrox.com,则对于 wrox.com的所有子域都有效)。如果没有明确设定,那么这个域会被认作来自设置 cookie 的那个域。- 路径(path):对于指定域中的那个路径,应该向服务器发送 cookie。例如,你可以指定 cookie 只有从 http://www.wrox.com/books/ 中才能访问,那么 http://www.wrox.com 的页面就不会发送 cookie 信息,即使请求都是来自同一个域的。
- 失效时间(expires):表示 cookie 何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个
cookie)。默认情况下,浏览器会话结束时即将所有 cookie 删除;不过也可以自己设置删除时间。 这个值是个 GMT 格式的日期(Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于指定应该删除 cookie 的准确时间。因此,cookie 可在浏览器关闭后依然保存在用户的机器上。如果你设置的失 效日期是个以前的时间,则 cookie 会被立刻删除。- 安全标志(secure):指定后,cookie 只有在使用 SSL 连接的时候才发送到服务器。例如,cookie 信息只 能发送给 https://www.wrox.com,而 http://www.wrox.com 的请求则不能发送 cookie
每一段信息都作为 Set-Cookie 头的一部分,使用分号加空格分隔每一段
Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com
*JavaScript 中的 cookie
document. cookie 属性。
- 当用来获取属性值时, document.cookie 返回当前页面可用的(根据 cookie 的域、路径、失效时间和安全设置)所有 cookie 的字符串,一系列由分号隔开的名值对儿.
- 当用于设置值的时候,document.cookie 属性可以设置为一个新的 cookie 字符串。这个 cookie 字
符串会被解释并添加到现有的 cookie 集合中。设置 document.cookie 并不会覆盖 cookie,除非设置的cookie 的名称已经存在。
*子 cookie
子 cookie 是存放在单个 cookie 中的更小段的数据。也就是使用 cookie 值来存储多个名称值对 儿。子 cookie 最常见的的格式如下所示。
name=name1=value1&name2=value2&name3=value3&name4=value4
(2) IE用户数据
在 IE5.0 中,微软通过一个自定义行为引入了持久化用户数据的概念。用户数据允许每个文档最多 128KB 数据,每个域名最多 1MB 数据。要使用
持久化用户数据
,首先必须如下所示,使用 CSS 在某个 元素上指定userData 行为
:
<div style="behavior:url(#default#userData)" id="dataStore"></div>
- 使用
setAttribute()方法
保存数据。- 为了将数据提交到浏览器缓存中,还必须调用
save()方法
并告诉它要保存到的数据空间的名字。数据空间名字可以完全任意,仅用于区分不同的数据集。
var dataStore = document.getElementById("dataStore");
dataStore.setAttribute("name", "Nicholas");
dataStore.setAttribute("book", "Professional JavaScript");
dataStore.save("BookInfo");
- 下一次页面载入之后,可以使用
load()方法
指定 同样的数据空间名称来获取数据。getAttribute()
调用了不存在的名称或者是尚未载入的名 称,则返回 null。
dataStore.load("BookInfo");
alert(dataStore.getAttribute("name")); //"Nicholas"
alert(dataStore.getAttribute("book")); //"Professional JavaScript"
- 通过
removeAttribute()方法
明确指定要删除某元素数据,只要指定属性名称。删除之后, 必须像下面这样再次调用 save()来提交更改。
dataStore.removeAttribute("name");
dataStore.removeAttribute("book");
dataStore.save("BookInfo");
(3) Web存储机制
*Storage 类型
- clear(): 删除所有值;Firefox 中没有实现 。
- getItem(name):根据指定的名字 name 获取对应的值。
- key(index):获得 index 位置处的值的名字。
- removeItem(name):删除由 name 指定的名值对儿。
- setItem(name, value):为指定的 name 设置一个对应的值。
*sessionStorage 对象
sessionStorage
对象存储特定于某个会话的数据,也就是该数据只保持到浏览器关闭。
- sessionStorage 对象其实是 Storage 的一个实例,所以可以使用 setItem()或者直接设。
- sessionStorage 中有数据时,可以使用 getItem()或者通过直接访问属性名来获取数据。
- 可以通过结合 length 属性和 key()方法来迭代 sessionStorage 中的值。
- 可以使用 for-in 循环来迭代 sessionStorage 中的值。
- 可以使用 delete 操作符删除对象属性,也可调用 removeItem()方法。
*globalStorage 对象
globalStorage
这个对象的目的是跨越会话存储数据,但有特定的访问限制。要使用 globalStorage,首先要指定哪些域可以访问该数据。可以通过方括号标记使用属性来实现。
- 对 globalStorage 空间的访问,是依据发起请求的页面的域名、协议和端口来限制的。
- 如果你事先不能确定域名,那么使用
location.host
作为属性名比较安全。- 如果不使用 removeItem()或者 delete 删除,或者用户未清除浏览器缓存,存储在 globalStorage 属性中的数据会一直保留在磁盘上。
*localStorage 对象
不能给localStorage
指定任何访问规则;规则事先就设定好了。要访问同一个 localStorage 对象,页面必须来自同一个域名(子域名无效),使用同一种 协议,在同一个端口上。这相当于 globalStorage[location.host]
。
*storage 事件
这个事件的
event 对象
有以下属性。
(1) domain:发生变化的存储空间的域名。
(2) key:设置或者删除的键名。
(3) newValue:如果是设置值,则是新值;如果是删除键,则是 null。
(4) oldValue:键被更改之前的值。
(4) IndexedDB
*数据库
IndexedDB
最大的特色是使用对象保存数据,而不是使用表来保存数据。一个 IndexedDB 数据库,就是 一组位于相同命名空间下的对象的集合。
var indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;
- 把要打开的数据库名传给
indexDB.open()
。如果传入的 数据库已经存在,就会发送一个打开它的请求;如果传入的数据库还不存在,就会发送一个创建并打开 它的请求。总之,调用 indexDB.open()会返回一个 IDBRequest 对象,在这个对象上可以添加 onerror 和 onsuccess 事件处理程序。
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;
};
(1)
event.target.result
中将有一个数据库实例对象(IDBData- base),这个对象会保存在 database 变量中。
(2) 如果发生了错误,那event.target.errorCode
中将 保存一个错误码,表示问题的性质。
- 默认情况下,IndexedDB 数据库是没有版本号的,最好一开始就为数据库指定一个版本号。为此, 可以调用
setVersion()方法
,传入以字符串形式表示的版本号。