突袭HTML5之Javascript API扩展3—本地存储全新体验


Posted in HTML / CSS onJanuary 31, 2013

为什么要存数据到客户端?
存储数据在客户端可以解决很多的问题和减少不必要的传输数据:
1. 能保存程序的状态:用户关闭浏览器再打开后能知道他工作到哪了。
2. 能缓存数据:很多不会变化的数据根本没必要每次都从服务端获取。
3. 能保存用户的喜好:这种数据通常不需要存在服务端。
以前的做法
在HTML5本地存储之前,如果我们想在客户端保存持久化数据,有这么几个选择:
1. HTTP cookie。HTTP cookie的缺点很明显,最多只能存储4KB的数据,每个HTTP请求都会被传送回服务器,明文传输(除非你使用SSL)。
2. IE userData。userData是微软在上世纪90年代的浏览器大战时推出的本地存储方案,借助DHTML的behaviour属性来存储本地数据, 允许每个页面最多存储64K数据,每个站点最多640K数据,userData的缺点显而易见,它不是Web标准的一部分,除非你的程序只需要支持IE, 否则它基本没什么用处。
3. Flash cookie。Flash cookie实际上和HTTP cookie并不是一回事,或许它的名字应该叫做"Flash本地存储”,Flash cookie默认允许每个站点存储不超过100K的数据,如果超出了,Flash会自动向用户请求更大的存储空间,借助Flash的 ExternalInterface接口,你可以很轻松地通过Javascript操作Flash的本地存储。Flash的问题很简单,就是因为它是 Flash。
4. Google Gears。Gears是Google在07年发布的一个开源浏览器插件,旨在改进各大浏览器的兼容性,Gears内置了一个基于SQLite的嵌入式 SQL数据库,并提供了统一API对数据库进行访问,在取得用户授权之后,每个站点可以在SQL数据库中存储不限大小的数据,Gears的问题就是 Google自己都已经不用它了。
眼花缭乱的各种技术导致的就是浏览器的兼容性问题。这里大家用的最多的可能就是cookie了。
HTML5中的全新体验
针对以上的问题,HTML5中给出了更加理想的解决方案:假如你需要存储的只是简单的用key/value对即可解决的数据,则可以使用Web Storage。
与Cookie相比,Web Storage存在不少的优势,概括为以下几点:
1. 存储空间更大:IE8下每个独立的存储空间为10M,其他浏览器实现略有不同,但都比Cookie要大很多。
2. 存储内容不会发送到服务器:当设置了Cookie后,Cookie的内容会随着请求一并发送的服务器,这对于本地存储的数据是一种带宽浪费。而Web Storage中的数据则仅仅是存在本地,不会与服务器发生任何交互。
3. 更多丰富易用的接口:Web Storage提供了一套更为丰富的接口,使得数据操作更为简便。
4. 独立的存储空间:每个域(包括子域)有独立的存储空间,各个存储空间是完全独立的,因此不会造成数据混乱。
Web Storage分类
Web Storage实际上由两部分组成:sessionStorage与localStorage。
sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。
localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。
检查是否支持Web Storage
Web Storage在各大主流浏览器中都支持了,但是为了兼容老的浏览器,还是要检查一下是否可以使用这项技术。
第一种方式:通过检查Storage对象是否存在来检查浏览器是否支持Web Storage:

复制代码
代码如下:

if(typeof(Storage)!=="undefined"){
// Yes! localStorage and sessionStorage support!
// Some code.....
} else {
// Sorry! No web storage support..
}

第二种方式就是分别检查各自的对象,例如检查localStorage是否支持:
复制代码
代码如下:

if (typeof(localStorage) == 'undefined' ) {
alert('Your browser does not support HTML5 localStorage. Try upgrading.');
} else {
// Yes! localStorage and sessionStorage support!
// Some code.....
}
或者:
if('localStorage' in window && window['localStorage'] !== null){
// Yes! localStorage and sessionStorage support!
// Some code.....
} else {
alert('Your browser does not support HTML5 localStorage. Try upgrading.');
}
或者
if (!!localStorage) {
// Yes! localStorage and sessionStorage support!
// Some code.....
} else {
alert('Your browser does not support HTML5 localStorage. Try upgrading.');
}

很显然第一个方式最直接,也最简单。
Web Storage的使用
Web Storage中存储的是键值对,而且浏览器会以字符串方式存储。记住在必要的时候将他们转为其他格式。
sessionStorage与localStorage除了用途不同外,成员列表是一样的:
复制代码
代码如下:

key = value: 存贮键值对
setItem(key, value): 存贮键值对
getItem(key): 取键值对
removeItem(key):移除所有键值对
clear():清空所有键值对
length:键值对的数目

这里还是要强调一下:setItem(key,value)方法中的value类型,理论上可以是任意类型,不过实际上浏览器会调用value的toString方法来获取其字符串值并存储到本地,因此如果是自定义的类型则需要自己定义有意义的toString方法。例如下面的例子结合JSON.stringify使用:
复制代码
代码如下:

var person = {'name': 'rainman', 'age': 24};
localStorage.setItem("me", JSON.stringify(person));
JSON.parse(localStorage.getItem('me')).name; // 'rainman'
/**
* JSON.stringify,将JSON数据转化为字符串
* JSON.stringify({'name': 'fred', 'age': 24}); // '{"name":"fred","age":24}'
* JSON.stringify(['a', 'b', 'c']); // '["a","b","c"]'
* JSON.parse,反解JSON.stringify
* JSON.parse('["a","b","c"]') // ["a","b","c"]
*/

此外,添加键值对的时候,如果添加的数量比较多,比较保险的做法是去检查是否有超出限额的异常:
复制代码
代码如下:

try {
localStorage.setItem(itemId, values.join(';'));
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
alert('Quota exceeded!');
}
}

Web Storage的方法非常简单,下面的示例是统计button点击的次数的:
复制代码
代码如下:

<!DOCTYPE html>
<html>
<head>
<script>
function clickCounter()
{
if(typeof(Storage)!=="undefined")
{
if (localStorage.clickcount)
{
localStorage.clickcount=Number(localStorage.clickcount)+1;
}
else
{
localStorage.clickcount=1;
}
document.getElementById("result").innerHTML="You have clicked the button " + localStorage.clickcount + " time(s).";
}
else
{
document.getElementById("result").innerHTML="Sorry, your browser does not support web storage...";
}
}
</script>
</head>
<body>
<p><button onclick="clickCounter()" type="button">Click me!</button></p>
<div id="result"></div>
<p>Click the button to see the counter increase.</p>
<p>Close the browser tab (or window), and try again, and the counter will continue to count (is not reset).</p>
</body>
</html>

在上面的例子中,你可以把localStorage换成sessionStorage,点击几次button然后验证在关闭浏览器前后的效果。
存在的问题
Web Storage的缺陷主要集中在其安全性方面,具体体现在以下两点:
1. 浏览器会为每个域分配独立的存储空间,即脚本在域A中是无法访问到域B中的存储空间的,但是浏览器却不会检查脚本所在的域与当前域是否相同。即在域B中嵌入域A中的脚本依然可以访问域B中的数据。
2. 存储在本地的数据未加密而且永远不会过期,极易造成隐私泄漏。
此外,更多的安全相关的问题请参看后面实用参考中的链接。
其他规范一览(仅供了解,说不定什么时候就没了)
Web Database
在老的HTML5提议中,假如你需要存储复杂的数据则可以使用Web Database,可以像客户端程序一样使用SQL(Web Database标准已被废弃,这里就是简单提一下);
globalStorage
这个也是html5中提出来,在浏览器关闭以后,使用globalStorage存储的信息仍能够保留下来,localStorage一样,域中任何一个页面存储的信息都能被所有的页面共享, 不过目前只有FireFox支持。
基本语法:
• globalStorage['developer.mozilla.org'] —— 在developer.mozilla.org下面所有的子域都可以通过这个命名空间存储对象来进行读和写。
• globalStorage['mozilla.org'] —— 在mozilla.org域名下面的所有网页都可以通过这个命名空间存储对象来进行读和写。
• globalStorage['org'] —— 在.org域名下面的所有网页都可以通过这个命名空间存储对象来进行读和写。
• globalStorage[''] —— 在任何域名下的任何网页都可以通过这个命名空间存储对象来进行读和写
方法属性:
• setItem(key, value) —— 设置或重置 key 值。
• getItem(key) —— 获取 key 值。
• removeItem(key) —— 删除 key 值。
• 设置 key 值:window.globalStorage["planabc.net"].key = value;
• 获取 key 值:value = window.globalStorage["planabc.net"].key;
其它特征:
• 过期时间同 localStorage,其它的一些特性也和localStorage相似。
• 现在Firefox只支持当前域下的globalStorage存储, 如果使用公用域会导致一个这样一个类似的错误“Security error” code: “1000”。
IndexedDB
最后我们要介绍的就是IndexedDB了,相比其他两个规范,目前只有Firefox实现了IndexedDB(顺便提一下,Mozilla表示它们永远不会去实现Web SQL Database),不过Google已经表示正在考虑在Chrome中加入IndexDB支持。
IndexedDB引入了一个object store的概念,这有点像是一个SQL Database,你可以在“数据库”中存储“记录”,并且每条“记录”可以拥有很多“字段",每个字段都有一个特定的数据类型,你可以选择记录的子集, 并使用“光标”进行遍历,同时object store中的所有变更都是基于“事务”的。
更多的信息参看后面使用参考中讲述FireFox中IndexedDB的文档。
实用参考:
官方文档:http://www.w3schools.com/html5/
三水点靠木:https://3water.com/w3school/html5/
本地存储的安全性:http://www.mhtml5.com/2012/03/4586.html
FireFox的实验特性IndexedDB:https://developer.mozilla.org/en-US/docs/IndexedDB
HTML / CSS 相关文章推荐
CSS3+DIV实现漂亮的动画彩色标签
Jun 16 HTML / CSS
移动端rem布局的两种实现方法
Jan 03 HTML / CSS
css3.0 图形构成实例练习二
Mar 19 HTML / CSS
基于CSS3特效之动画:animation的应用
May 09 HTML / CSS
html5+css3之CSS中的布局与Header的实现
Nov 21 HTML / CSS
HTML5 Geolocation API的正确使用方法
Dec 04 HTML / CSS
网易微博Web App用HTML5开发的过程介绍
Jun 13 HTML / CSS
html5中地理位置定位api接口开发应用小结
Jan 04 HTML / CSS
HTML5 中新的全局属性(整理)
Jul 31 HTML / CSS
解析HTML5中的新功能本地存储localStorage
Mar 01 HTML / CSS
详解移动端h5页面根据屏幕适配的四种方案
Apr 15 HTML / CSS
使用css样式设计一个简单的html登陆界面的实现
Mar 30 HTML / CSS
突袭HTML5之Javascript API扩展2—地理信息服务及地理位置API学习
Jan 31 #HTML / CSS
突袭HTML5之Javascript API扩展1—Web Worker异步执行及相关概述
Jan 31 #HTML / CSS
HTML5之SVG 2D入门13—svg对决canvas及长处和适用场景分析
Jan 30 #HTML / CSS
HTML5之SVG 2D入门12—SVG DOM及DOM操作介绍
Jan 30 #HTML / CSS
HTML5之SVG 2D入门11—用户交互性(动画)介绍及应用
Jan 30 #HTML / CSS
HTML5之SVG 2D入门10—滤镜的定义及使用
Jan 30 #HTML / CSS
HTML5之SVG 2D入门9—蒙板及mask元素介绍与应用
Jan 30 #HTML / CSS
You might like
php生成xml简单实例代码
2009/12/16 PHP
PHP基于GD库的缩略图生成代码(支持jpg,gif,png格式)
2014/06/19 PHP
php实现与erlang的二进制通讯实例解析
2014/07/23 PHP
从wamp到xampp的升级之路
2015/04/08 PHP
php简单获取复选框值的方法
2016/05/11 PHP
Yii框架数据模型的验证规则rules()被执行的方法
2016/12/02 PHP
深入理解JavaScript高级之词法作用域和作用域链
2013/12/10 Javascript
jQuery中clearQueue()方法用法实例
2014/12/29 Javascript
JS控制div跳转到指定的位置的几种解决方案总结
2016/11/05 Javascript
浅谈js原生拖放
2016/11/21 Javascript
Angular中$broadcast和$emit的使用方法详解
2017/05/22 Javascript
Vue+webpack项目基础配置教程
2018/02/12 Javascript
Python中os.path用法分析
2015/01/15 Python
python通过yield实现数组全排列的方法
2015/03/18 Python
python在控制台输出进度条的方法
2015/06/20 Python
设计模式中的原型模式在Python程序中的应用示例
2016/03/02 Python
使用Python的Twisted框架构建非阻塞下载程序的实例教程
2016/05/25 Python
Python中格式化format()方法详解
2017/04/01 Python
Python读取文件内容的三种常用方式及效率比较
2017/10/07 Python
Python语言描述随机梯度下降法
2018/01/04 Python
python中的常量和变量代码详解
2018/07/25 Python
浅谈tensorflow中几个随机函数的用法
2018/07/27 Python
使用Python快乐学数学Github万星神器Manim简介
2019/08/07 Python
PyTorch学习:动态图和静态图的例子
2020/01/06 Python
pytorch 常用线性函数详解
2020/01/15 Python
使用canvas对多图片拼合并导出图片的方法
2018/08/28 HTML / CSS
世界领先的豪华床上用品供应商之一:Bedeck Home
2019/03/18 全球购物
计算机专业自荐信
2013/10/14 职场文书
2014年幼儿园后勤工作总结
2014/11/10 职场文书
优秀学生干部事迹材料
2014/12/24 职场文书
先进党员事迹材料
2014/12/24 职场文书
教师个人师德工作总结2015
2015/05/12 职场文书
小学五年级班主任工作经验交流材料
2015/11/02 职场文书
python 如何获取页面所有a标签下href的值
2021/05/06 Python
Vue中foreach数组与js中遍历数组的写法说明
2021/06/05 Vue.js
Win11怎么把合并的任务栏分开 Win11任务栏合并分开教程
2022/04/06 数码科技