23.3.3 Web存储机制【JavaScript高级程序设计第三版】

Web Storage 最先是在Web 超文本应用技术工做组(WHAT-WG)的Web 应用1.0 规范中描述的。
这个规范的最初的工做最终成为了HTML5 的一部分。Web Storage 的目的是克服由cookie 带来的一些限制,当数据须要被严格控制在客户端上时,无须持续地将数据发回服务器。Web Storage 的两个主要目标是:web

  • 提供一种在cookie 以外存储会话数据的途径;
  • 提供一种存储大量能够跨会话存在的数据的机制。

最初的Web Storage 规范包含了两种对象的定义:sessionStorage 和globalStorage。这两个对象在支持的浏览器中都是以windows 对象属性的形式存在的,支持这两个属性的浏览器包括IE8+、Firefox 3.5+、Chrome 4+和Opera 10.5+。
Firefox 2 和3 基于早期规范的内容部分实现了Web Storage,当时只实现了globalStorage,没有实现localStorage。windows

1. Storage 类型

Storage 类型提供最大的存储空间(因浏览器而异)来存储名值对儿。Storage 的实例与其余对象相似,有以下方法。api

  • clear(): 删除全部值;Firefox 中没有实现 。
  • getItem(name):根据指定的名字name 获取对应的值。
  • key(index):得到index 位置处的值的名字。
  • removeItem(name):删除由name 指定的名值对儿。
  • setItem(name, value):为指定的name 设置一个对应的值。

其中,getItem()、removeItem()和setItem()方法能够直接调用,也可经过Storage 对象间接调用。由于每一个项目都是做为属性存储在该对象上的,因此能够经过点语法或者方括号语法访问属性来读取值,设置也同样,或者经过delete 操做符进行删除。不过,咱们还建议读者使用方法而不是属性来访问数据,以避免某个键会意外重写该对象上已经存在的成员。
还可使用length 属性来判断有多少名值对儿存放在Storage 对象中。但没法判断对象中全部数据的大小,不过IE8 提供了一个remainingSpace 属性,用于获取还可使用的存储空间的字节数。Storage 类型只能存储字符串。非字符串的数据在存储以前会被转换成字符串。浏览器

2. sessionStorage 对象

sessionStorage 对象存储特定于某个会话的数据,也就是该数据只保持到浏览器关闭。这个对象就像会话cookie,也会在浏览器关闭后消失。存储在sessionStorage 中的数据能够跨越页面刷新而存在,同时若是浏览器支持,浏览器崩溃并重启以后依然可用(Firefox 和WebKit 都支持,IE 则不行)。
由于seesionStorage 对象绑定于某个服务器会话,因此当文件在本地运行的时候是不可用的。存储在sessionStorage 中的数据只能由最初给对象存储数据的页面访问到,因此对多页面应用有限制。因为sessionStorage 对象实际上是Storage 的一个实例,因此可使用setItem()或者直接设置新的属性来存储数据。下面是这两种方法的例子。缓存

//使用方法存储数据
sessionStorage.setItem("name", "Nicholas");
//使用属性存储数据
sessionStorage.book = "Professional JavaScript";

不一样浏览器写入数据方面略有不一样。Firefox 和WebKit 实现了同步写入,因此添加到存储空间中的数据是马上被提交的。而IE 的实现则是异步写入数据,因此在设置数据和将数据实际写入磁盘之间可能有一些延迟。对于少许数据而言,这个差别是能够忽略的。对于大量数据,你会发现IE 要比其余浏览器更快地恢复执行,由于它会跳过实际的磁盘写入过程。
在IE8 中能够强制把数据写入磁盘:在设置新数据以前使用begin()方法,而且在全部设置完成以后调用commit()方法。看如下例子。安全

//只适用于IE8
sessionStorage.begin();
sessionStorage.name = "Nicholas";
sessionStorage.book = "Professional JavaScript";
sessionStorage.commit();

这段代码确保了name 和book 的值在调用commit()以后马上被写入磁盘。调用begin()是为了确保在这段代码执行的时候不会发生其余磁盘写入操做。对于少许数据而言,这个过程不是必需的;不过,对于大量数据(如文档之类的)可能就要考虑这种事务形式的方法了。sessionStorage 中有数据时,可使用getItem()或者经过直接访问属性名来获取数据。两种方法的例子以下。服务器

//使用方法读取数据
var name = sessionStorage.getItem("name");
//使用属性读取数据
var book = sessionStorage.book;

还能够经过结合length 属性和key()方法来迭代sessionStorage 中的值,以下所示。cookie

for (var i = 0,
len = sessionStorage.length; i < len; i++) {
	var key = sessionStorage.key(i);
	var value = sessionStorage.getItem(key);
	alert(key + "=" + value);
}

它是这样遍历sessionStorage 中的名值对儿的:首先经过key()方法获取指定位置上的名字,而后再经过getItem()找出对应该名字的值。还可使用for-in 循环来迭代sessionStorage 中的值:session

for (var key in sessionStorage) {
	var value = sessionStorage.getItem(key);
	alert(key + "=" + value);
}

每次通过循环的时候,key 被设置为sessionStorage 中下一个名字,此时不会返回任何内置方法或length 属性。要从sessionStorage 中删除数据,可使用delete 操做符删除对象属性,也可调用removeItem()方法。如下是这些方法的例子。dom

//使用delete 删除一个值——在WebKit 中无效
delete sessionStorage.name;
//使用方法删除一个值
sessionStorage.removeItem("book");

运行一下
在撰写本书时,delete 操做符在WebKit 中没法删除数据,removeItem()则能够在各类支持的浏览器中正确运行。sessionStorage 对象应该主要用于仅针对会话的小段数据的存储。若是须要跨越会话存储数据,那么globalStorage 或者localStorage 更为合适。

3. globalStorage 对象

Firefox 2 中实现了globalStorage 对象。做为最初的Web Storage 规范的一部分,这个对象的目的是跨越会话存储数据,但有特定的访问限制。要使用globalStorage,首先要指定哪些域能够访问该数据。能够经过方括号标记使用属性来实现,如如下例子所示。

//保存数据
globalStorage["wrox.com"].name = "Nicholas";
//获取数据
var name = globalStorage["wrox.com"].name;

在这里,访问的是针对域名wrox.com 的存储空间。globalStorage 对象不是Storage 的实例,而具体的globalStorage["wrox.com"]才是。这个存储空间对于wrox.com 及其全部子域都是能够访问的。能够像下面这样指定子域名。

//保存数据
globalStorage["www.wrox.com"].name = "Nicholas";
//获取数据
var name = globalStorage["www.wrox.com"].name;

这里所指定的存储空间只能由来自www.wrox.com 的页面访问,其余子域名都不行。
某些浏览器容许更加宽泛的访问限制,好比只根据顶级域名进行限制或者容许全局访问,以下面例子所示。

//存储数据,任何人均可以访问——不要这样作!
globalStorage[""].name = "Nicholas";
//存储数据,可让任何以.net 结尾的域名访问——不要这样作!
globalStorage["net"].name = "Nicholas";

虽然这些也支持,可是仍是要避免使用这种可宽泛访问的数据存储,以防止出现潜在的安全问题。
考虑到安全问题,这些功能在将来可能会被删除或者是被更严格地限制,因此不该依赖于这类功能。当使用globalStorage 的时候必定要指定一个域名。
对globalStorage 空间的访问,是依据发起请求的页面的域名、协议和端口来限制的。例如,若是使用HTTPS 协议在wrox.com 中存储了数据,那么经过HTTP 访问的wrox.com 的页面就不能访问该数据。一样,经过80 端口访问的页面则没法与同一个域一样协议但经过8080 端口访问的页面共享数据。这相似于Ajax 请求的同源策略。globalStorage 的每一个属性都是Storage 的实例。所以,能够像以下代码中这样使用。

globalStorage["www.wrox.com"].name = "Nicholas";
globalStorage["www.wrox.com"].book = "Professional JavaScript";
globalStorage["www.wrox.com"].removeItem("name");
var book = globalStorage["www.wrox.com"].getItem("book");

若是你事先不能肯定域名,那么使用location.host 做为属性名比较安全。例如:

globalStorage[location.host].name = "Nicholas";
var book = globalStorage[location.host].getItem("book");

运行一下
若是不使用removeItem() 或者delete 删除, 或者用户未清除浏览器缓存, 存储在globalStorage 属性中的数据会一直保留在磁盘上。这让globalStorage 很是适合在客户端存储文档或者长期保存用户偏好设置。

4. localStorage 对象

localStorage 对象在修订过的HTML 5 规范中做为持久保存客户端数据的方案取代了globalStorage。与globalStorage 不一样,不能给localStorage 指定任何访问规则;规则事先就设定好了。要访问同一个localStorage 对象,页面必须来自同一个域名(子域名无效),使用同一种协议,在同一个端口上。这至关于globalStorage[location.host]。
因为localStorage 是Storage 的实例,因此能够像使用sessionStorage 同样来使用它。下面是一些例子。

//使用方法存储数据
localStorage.setItem("name", "Nicholas");
//使用属性存储数据
localStorage.book = "Professional JavaScript";
//使用方法读取数据
var name = localStorage.getItem("name");
//使用属性读取数据
var book = localStorage.book;

运行一下
存储在localStorage 中的数据和存储在globalStorage 中的数据同样,都遵循相同的规则:数据保留到经过JavaScript 删除或者是用户清除浏览器缓存。为了兼容只支持globalStorage 的浏览器,可使用如下函数。

function getLocalStorage() {
	if (typeof localStorage == "object") {
		return localStorage;
	} else if (typeof globalStorage == "object") {
		return globalStorage[location.host];
	} else {
		throw new Error("Local storage not available.");
	}
}

而后,像下面这样调用一次这个函数,就能够正常地读写数据了。

var storage = getLocalStorage();

运行一下
在肯定了使用哪一个Storage 对象以后,就能在全部支持Web Storage 的浏览器中使用相同的存取规则操做数据了。

5. storage 事件

对Storage 对象进行任何修改,都会在文档上触发storage 事件。当经过属性或setItem()方法保存数据,使用delete 操做符或removeItem()删除数据,或者调用clear()方法时,都会发生该事件。这个事件的event 对象有如下属性。

  • domain:发生变化的存储空间的域名。
  • key:设置或者删除的键名。
  • newValue:若是是设置值,则是新值;若是是删除键,则是null。
  • oldValue:键被更改以前的值。

在这四个属性中,IE8 和Firefox 只实现了domain 属性。在撰写本书的时候,WebKit 尚不支持storage 事件:如下代码展现了如何侦听storage 事件:

EventUtil.addHandler(document, "storage", function(event){
    alert("Storage changed for " + event.domain);
});

运行一下
不管对sessionStorage、globalStorage 仍是localStorage 进行操做,都会触发storage事件,但不做区分。

6. 限制

与其余客户端数据存储方案相似,Web Storage 一样也有限制。这些限制因浏览器而异。通常来讲,对存储空间大小的限制都是以每一个来源(协议、域和端口)为单位的。换句话说,每一个来源都有固定大小的空间用于保存本身的数据。考虑到这个限制,就要注意分析和控制每一个来源中有多少页面须要保存数据。
对于localStorage 而言,大多数桌面浏览器会设置每一个来源5MB 的限制。Chrome 和Safari 对每一个来源的限制是2.5MB。而iOS 版Safari 和Android 版WebKit 的限制也是2.5MB。
对sessionStorage 的限制也是因浏览器而异。有的浏览器对sessionStorage 的大小没有限制,但Chrome、Safari、iOS 版Safari 和Android 版WebKit 都有限制,也都是2.5MB。IE8+和Opera 对sessionStorage 的限制是5MB。

有关Web Storage 的限制,请参考http://dev-test.nemikor.com/web-storage/support-test/。

 

下载离线版教程:http://www.shouce.ren/api/view/a/15218

相关文章
相关标签/搜索