zoukankan      html  css  js  c++  java
  • 23.3.3 Web存储机制【JavaScript高级程序设计第三版】

    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

  • 相关阅读:
    LeetCode(111) Minimum Depth of Binary Tree
    LeetCode(108) Convert Sorted Array to Binary Search Tree
    LeetCode(106) Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode(105) Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode(99) Recover Binary Search Tree
    【Android】通过经纬度查询城市信息
    【Android】自定义View
    【OpenStack Cinder】Cinder安装时遇到的一些坑
    【积淀】半夜突然有点想法
    【Android】 HttpClient 发送REST请求
  • 原文地址:https://www.cnblogs.com/itzhoubao/p/6843926.html
Copyright © 2011-2022 走看看