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

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

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

1. Storage 类型

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

  • 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 中的值,如下所示。

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 中的值:

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

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

//使用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

23.3.3 Web存储机制【JavaScript高级程序设计第三版】的更多相关文章

  1. JavaScript高级程序设计第三版.CHM【带实例】

    从驱动全球商业.贸易及管理领域不计其数的复杂应用程序的角度来看,说 JavaScript 已经成为当今世界上最流行的编程语言一点儿都不为过. JavaScript 是一种非常松散的面向对象语言,也是 ...

  2. javascript高级程序设计第三版书摘

    在HTML 中使用JavaScript <script>元素 在使用<script>元素嵌入 JavaScript 代码时,只须为<script>指定 type 属 ...

  3. 22.1 高级函数【JavaScript高级程序设计第三版】

    函数是JavaScript 中最有趣的部分之一.它们本质上是十分简单和过程化的,但也可以是非常复杂和动态的.一些额外的功能可以通过使用闭包来实现.此外,由于所有的函数都是对象,所以使用函数指针非常简单 ...

  4. 4.2 执行环境及作用域【JavaScript高级程序设计第三版】

    执行环境(execution context,为简单起见,有时也称为“环境”)是JavaScript 中最为重要的一个概念.执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为.每个执行环 ...

  5. 14.5 富文本编辑【JavaScript高级程序设计第三版】

    富文本编辑,又称为WYSIWYG(What You See Is What You Get,所见即所得).在网页中编辑富文本内容,是人们对Web 应用程序最大的期待之一.虽然也没有规范,但在IE 最早 ...

  6. DOM 操作技术【JavaScript高级程序设计第三版】

    很多时候,DOM 操作都比较简明,因此用JavaScript 生成那些通常原本是用HTML 代码生成的内容并不麻烦.不过,也有一些时候,操作DOM 并不像表面上看起来那么简单.由于浏览器中充斥着隐藏的 ...

  7. 模拟事件【JavaScript高级程序设计第三版】

    事件,就是网页中某个特别值得关注的瞬间.事件经常由用户操作或通过其他浏览器功能来触发.但很少有人知道,也可以使用JavaScript 在任意时刻来触发特定的事件,而此时的事件就如同浏览器创建的事件一样 ...

  8. 21.1 XMLHttpRequest 对象【JavaScript高级程序设计第三版】

    IE5 是第一款引入XHR 对象的浏览器.在IE5 中,XHR 对象是通过MSXML 库中的一个ActiveX对象实现的.因此,在IE 中可能会遇到三种不同版本的XHR 对象,即MSXML2.XMLH ...

  9. 13.6 模拟事件【JavaScript高级程序设计第三版】

    事件,就是网页中某个特别值得关注的瞬间.事件经常由用户操作或通过其他浏览器功能来触发. 但很少有人知道,也可以使用JavaScript 在任意时刻来触发特定的事件,而此时的事件就如同浏览器创建的事件一 ...

随机推荐

  1. 18_Condition条件

    [简述] wait()和notify()方法是和synchronized关键字合作使用的. Condition是和重入锁相关联的,通过ReentrantLock.newCondition()生成一个与 ...

  2. solidity语言2

    变量类型(Value Types) # 布尔型 关键字 bool 值 true , false 操作符 !, &&, ||, ==, != # 整型 关键字 int(int256), ...

  3. c++链表实现学生成绩管理系统(简易版)

    #include<iostream> using namespace std; typedef struct student{ int id;//学号 string sex; string ...

  4. MySQL的基础(优化)3

    今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们程序员需要去关注的事情.当我们去设计数据库表结构,对操作数据 ...

  5. 用大白话告诉你什么是Event Loop

    文章原文地址 前沿 从前有座山,山里有座庙,庙里有个小和尚在讲故事.讲什么呢?讲的是: 从前有座山,山里有座庙,庙里有个小和尚在讲故事.讲什么呢?讲的是: 从前有座山,山里有座庙,庙里有个小和尚在讲故 ...

  6. 扫描FTP,保存文件

    1.需求:某公司ftp服务器中一个文件夹中有30个文件(文件名字是不同的),每五分钟产生一个新的文件,同时删除这三十个文件中最早产生的文件,该文件夹中始终保持30个文件. 现在需要采集一周的数据做研究 ...

  7. Windows 系统 Unicode 文件名操作(新建、重命名、枚举、复制)全攻略

    常见的那些文件操作函数都不支持,于是为了达到目的,需要各种方法配合,应该是不如其他语言方便.我只是想看看Perl到底是否适合做这件事,于是折腾了一回. 文件的建立: 模块:Win32 Code: [全 ...

  8. CRM和ERP的Sales Organization的映射关系

    在如下的配置里可以维护CRM和ERP的Sales Organization的映射关系. 例如,ERP的编号为0001的销售组织映射到CRM的编号为O 50040102的销售组织: 这种映射关系存储在表 ...

  9. IOS 摇一摇的方法

    ● 监控摇一摇的方法 ● 方法1:通过分析加速计数据来判断是否进行了摇一摇操作(比较复杂) ● 方法2:iOS自带的Shake监控API(非常简单) ● 判断摇一摇的步骤:实现3个摇一摇监听方法 ● ...

  10. 什么是React中的组件

    组件就是页面上的一部分.如图,左边是一个网页.右边是对应的一个组件图.我们可以把一个大的网页拆分成很多小的部分.比如标题部分,对应一个组件,就是标题组件.搜索部分,对应的组件就是搜索组件.而这个搜索组 ...