首页 » HTML » Web存储机制(Web Storage)

Web存储机制(Web Storage)

Web Storage最早是在Web超文本应用技术工作组的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。

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类型只能存储字符串。非字符串的数据在存储之前会被转换成字符串。

sessionStorage对象

sessionStorage对象存储特定于某个会话的数据,也就是该数据只保持到该浏览器关闭。这个对象就像会话cookie,也会在浏览器关闭后消失。存储在sessionStorage中的数据可以跨越页面刷新而存在,同时如果浏览器支持,浏览器崩溃并重启之后依然可用(Firefox和WebKit都支持,IE则不行)。

因为sessionStorage对象绑定于某个服务器会话,所以当文件在本地运行的时候是不可用的。存储在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删除一个值
delete sessionStorage.name;
//使用方法删除一个值
sessionStorage.removeItem("book");

sessionStorage对象应该主要用于针对该会话的小段数据存储。如果需要跨越会话存储数据,那么globalStorage或者localStorage更为合适。

globalStorage对象

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

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

这里所指定的存储空间只能由来自www.w3cmm.com的页面访问,其它子域名都不行。

某些浏览器允许更加宽泛的访问限制,比如只根据顶级域名进行限制或者允许全局访问,如下面例子所示:

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

虽然这些也支持,但是还是要避免使用这种可宽泛访问的数据存储,以防止出现潜在的安全问题。考虑到安全问题,这些功能在未来可能会被删除或着是被更严格的限制,所以不应依赖于这类功能。当使用globalStorage的时候一定要指定一个域名。

对globalStorage空间的访问,是一句发起请求的页面的域名、协议和端口来限制的。例如,如果使用HTTPS协议在w3cmm.com中存储了数据,那么通过HTTP访问的w3cmm.com的页面就不能访问该数据。同样,通过80端口访问的页面则无法与同一个域协议但通过8080端口访问的页面共享数据。这类似与Ajax请求的同源策略。

globalStorage的每个属性都是Storage的实例。因此,可以像如下代码中这样使用。

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

如果你事先不能确定域名,那么使用location.host作为属性名比较安全。例如:

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

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

localStorage对象

localStorage对象在修订过的HTML5规范中作为持久保存在客户端数据的方案取代了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的浏览器中使用相同的存取规则操作数据了。

storage事件

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

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

在这四个属性中,IE8和Firefox只实现了domain属性。

以下代码展示了如何侦听storage事件:

var EventUtil = {
    addHandler: function (element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    }
};
EventUtil.addHandler(document, "storage", function(event) {
    alert("Storage changed for " + event.domain);
});

无论对sessionStorage、globalStorage还是localStorage进行操作,都会触发storage事件,但不作区分。

限制

与其它客户端数据存储方案类似,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。

此文章发表在 HTML. 将 固定链接 加入收藏.