在web应用程序中,持久化本地存储在本地应用中占据很大优势。在本地应用中,操作系统会提供一个抽象层用于存储和检索应用中特定的数据如运行时状态等。这些值可能存储在注册表里,INI文件中,XML文件或者一些平台相关的地方。如果说你本地应用中需要使用到键值匹配的形式,你可以使用数据库,编写一套特有的文件格式或者其他很多方法。
但长久以来,web应用中没有权限进行这些操作。早期我们使用Cookies来进行一些本地存储工作。但它有以下三个潜在的问题:
- Cookies会包含在每个HTTP的请求中,但大部分时间Cookies中的值都是相同的,这会导致web应用的反应速度降低
- 由于Cookies会在HTTP请求中发送,而且发送的数据在没有使用SSL的情况下是未加密的,这会带来安全性问题
- Cookies的大小限制为4KB,有时候这完全不够
我们真正希望的本地存储可以拥有以下功能:
- 大量的存储空间
- 存储在客户端
- 可持久的
- 不会传送到服务端
在HTML5之前, 有很多不同的方式来实现上述功能,但都很杂乱且不能完全达到要求。
在HTML5之前的那些本地存储技术
在浏览器大战时代,微软发明了很多东西用于增加竞争力。其中有一个叫做DHTML行为,这些行为中有一个叫做userData.
userData允许网页在每个域以XML的形式存储达64KB的数据(如果是可信用域如内部网络可以存储640KB的数据),这似乎已经足够使用。不过IE没有向用户提供一个窗口用来提醒用户,并且不能提升存储的能力。
2002年,Adobe在flash 6中创造了一个feature,后来被误读为"Flash Cookie"。这个模块其实就是一个本地共享对象,它可以在每个域中存储100KB的数据。Brad Neuberg开发了一个早期的模型AMASS,他构建了Flash到Javascript的桥梁,但它有一些Flash设计模式上的限制。到了2006年,随着flash 8中带来的外部接口功能,从Javascript中访问本地存储对象有了一个数量级的提升。Brad重写了AMASS,并且把它集成到了Dojo Toolkit里。Flash允许每个域可以轻松存储100KB,如果超过100KB,它会弹出提示框让用户选择是否允许增加数据存储空间。
2007年,谷歌发布了一个开源的浏览器插件Gears用于扩展浏览器额外的能力。Gears提供给我们开放接口用于访问一个基于SQLite的数据库。到了2010年,谷歌开始将Gears的一些能力转移到HTML5的web标准中,最后Gears停止更新了。
观察上面这些解决方案,可以发现:这些方案不是针对特定浏览器就是需要依赖于第三方插件。尽管有许多方式来解决这些问题,但他们的实现方式,接口,存储限制,用户体验等等都不一致。最终HTML5出现了,它旨在解决:提供一个标准的API,使多个浏览器保持一致性,而且不依赖第三方插件。
HTML Storage
我们一般说到的"HTML5 Storage"一般又叫做 Web Storage.它是HTML5中的一个规范,但由于一些政治因素,在实现上被分割了。有些浏览器厂商把它叫做"Local Storage"或者"DOM Storage"。根据一些相关性命名方式可能更复杂。
HTML5 Storage简单地来说就是一种本地键值对存储形式。和Cookies一样,它是会持久存储在本地的,不会因为关闭浏览器等操作而消失。但不同的是它不会自动传送到服务端,它被集成到了浏览器中,因而不需要安装第三方插件。
下表是HTML5 Storage各个浏览器的支持情况:
IE | FIREFOX | SAFARI | CHROME | OPERA | IPHONE | ANDROID |
---|---|---|---|---|---|---|
8.0+ | 3.5+ | 4.0+ | 4.0+ | 10.5+ | 2.0+ | 2.0+ |
在使用之前,我们需要检测浏览器是否支持。
1 function supports_html5_storage(){ 2 try{ 3 return 'localStorage' in window && window['localStorage'] != null; 4 } catch (e) { 5 return false; 6 } 7 }
或者我们使用Modernizr来检测
1 if (Modernizr.localstorage) { 2 // window.localStorage is available! 3 } else { 4 // no native support for HTML5 storage :( 5 // maybe try dojox.storage or a third-party solution 6 }
如何使用HTML5 STORAGE
我们知道HTML5 Storage是基于键值对的。其中的键是一个字符串。而数据可以支持各种形式如字符串,布尔值,整形,浮点型等。但是实际上,数据还是会存储成字符串型。因此如果如果检索到数据后,我们需要手动去将字符串数据转换成相应我们原来的形式。
1 interface Storage { 2 getter any getItem(in DOMString key); 3 setter creator void setItem(in DOMString key, in any data); 4 };
当使用setItem给同一个key赋值时,它会覆盖之前的值,如果用getItem获取一个不存在的key,它返回的是null。
除了用setItem和getItem来进行赋值和检索外,我们还可以使用数组索引的形式
var foo = localStorage["bar"]; // ... localStorage["bar"] = foo;
如果需要移除某个key或者清楚整个存储区域,可以使用removeItem和clear函数。
interface Storage { deleter void removeItem(in DOMString key); void clear(); };
HTML5 Storage还提供了一个属性获取数据总数和一个key函数用于支持直接通过索引位置获取数据。
interface Storage { readonly attribute unsigned long length; getter DOMString key(in unsigned long index); };
HTML5 Storage事件
如果我们需要在本地存储数据改变的时候进行一些操作,我们可以追踪storage事件。storage事件会在数据真正改变的时候触发。
storage事件的一般使用方式如下
1 if (window.addEventListener) { 2 window.addEventListener("storage", handle_storage, false); 3 } else { 4 window.attachEvent("onstorage", handle_storage); 5 }; 6 function handle_storage(e) { 7 if (!e) { e = window.event; } 8 }
其中回掉的参数是一个StorageEvent对象,包含以下几个有用的属性。
属性 | 类型 | 描述 |
---|---|---|
* note: 有些时候,url属性又叫做uri,因此为了兼容性,我们需要检测是否支持url属性,不支持的话再去check uri属性 | ||
key | string | 键值名 |
oldValue | any | 更改之前的键值,如果是新增的话,该值为null |
newValue | any | 改变后的值,如果是移除操作的话,该值为null |
url * | string | 触发该事件的操作所在的页面url |
需要注意的是,storage事件只是用于通知有改变,我们不能够对这个改变进行任何修改操作。
目前的浏览器中的一些限制
目前的一些限制,归结来说就是3个词"5 megabytes","QUOTA_EXCEEDED_ERR"和"no"。
"5 megabytes"表示每个源(源是HTML5中引入的概念,是web安全模型的基础单元,参照rfc6454为什么引入源)。需要注意的是数据是以字符串的形式存储的,因此数据的大小并不是它本身所占大小,而是其字符串所占大小。
"QUOTA_EXCEEDED_ERR",当存储数据超过5m时,会抛出这个异常。"no"表明我们不可以向用户请求额外的存储空间。
HTML STORAGE应用
下面来讲解一个demo,先空着,等写完五子棋应用再来不上。。。。。。。
更多的本地存储方式
07年的时候,Google发布了Gears,里面包含了一个内嵌数据库SQLite。这个早期的原型直接影响了后来Web SQL Database的具体创建。"WebDB"提供了一个简单的SQL 数据库封装,允许你在javascript中向使用sql一样,很有趣!
1 openDatabase('documents', '1.0', 'Local document storage', 5*1024*1024, function (db) { 2 db.changeVersion('', '1.0', function (t) { 3 t.executeSql('CREATE TABLE docids (id, name)'); 4 }, error); 5 });
目前WebDB的支持情况
IE | FIREFOX | SAFARI | CHROME | OPERA | IPHONE | ANDROID |
---|---|---|---|---|---|---|
· | · | 4.0+ | 4.0+ | 10.5+ | 3.0+ | 2.0+ |
由于在SQL的世界杂乱纷繁,很难形成一个标准化的规范。这种情况下,我们来介绍另外一种数据存储方式,叫做"WebSimpleDB",又叫"IndexedDB"。
IndexedDB提供了一个 store对象。它里面实现了很多SQL数据库的概念,数据库有许多集合,每个集合又有很多字段,每个字段拥有特定的数据类型。我们可以选定一个集合,使用游标来遍历它。
更多的阅读
HTML5 storage:
- HTML5 Storage specification
- Introduction to DOM Storage on MSDN
- Web Storage: easier, more powerful client-side data storage on Opera Developer Community
- DOM Storage on Mozilla Developer Center. (Note: most of this page is devoted to Firefox’s prototype implementation of a
globalStorage
object, a non-standard precursor tolocalStorage
. Mozilla added support for the standardlocalStorage
interface in Firefox 3.5.) - Unlock local storage for mobile Web applications with HTML5, a tutorial on IBM DeveloperWorks
Early work by Brad Neuberg et. al. (pre-HTML5):
- Internet Explorer Has Native Support for Persistence?!?! (about the
userData
object in IE) - Dojo Storage, part of a larger tutorial about the (now-defunct) Dojo Offline library
dojox.storage.manager
API reference- dojox.storage Subversion repository
Web SQL Database:
- Web SQL Database specification
- Introducing Web SQL Databases
- Web Database demonstration
- persistence.js, an “asynchronous JavaScript ORM” built on top of Web SQL Database and Gears
IndexedDB: