目前在用户的网络浏览器中保存大量数据需要遵循几大现有标准,每一种标准都拥有自己的优势、短板、独特的W3C标准化状态以及浏览器支持级别。但无论如何,这些标准的实际表现都优于广泛存在的cookies机制。
今天的Web应用程序开始在客户端中执行大量数据处理工作,甚至可能需要以脱机方式完成任务。可以说,客户端数据存储对于下一代Web应用程序的发展起到了至关重要的作用。
然而直到现在,cookies仍然是用户浏览器中最常见的数据存储机制。如果一款Web应用需要重复访问某些数据,则只有两种方式可供选择:要么再次向服务器发送请求以获取数据,要么读取保存在cookies中的内容。
cookies机制只能提供有限的存储空间——最多4K或者4096字节——因此总量较大的数据会被拆分成4K大小的块从而加以明确而直接地管理。
但这种方式对于存储的协作及管理而言显然并不可行,因此我们需要拿出一套新的替代性方案。
cookies的承受能力太过孱弱
网络浏览器最初只是通过HTTP并解析HTML实现应用程序对文档内容的加载。但在此后不久,第一款网景浏览器出现了,它满足了用户的一系列实际需 求,但却需要利用本质上无状态的HTTP协议来通过某些机制实现状态追踪。面对这一问题,Lou Montulli于1994年创造了浏览器cookie(当初被称为‘magic cookie’),并首次亮相于Mosiac网景浏览器0.9b版本之上。
在通用网关接口(简称CGI)提供的服务器端脚本访问功能与cookies的共同辅助下,最早的Web应用程序终于变成现实。最终,我们开始沿着这条小路将浏览器转化成为一种通用的应用程序平台。
然而cookies机制存在着严重缺陷。正如前面所提到,它只能存储极少量数据,而且很容易受到各类攻击活动的影响,这样的状况让我们很难利用其存储个人信息及敏感数据、从而极大限制了它的使用范围。
cookies会介入到从浏览器发向服务器端的每一条HTTP请求当中。假设一个网页中包含的四张图片、一个外部CSS文档外加JavaScript 文档。系统会为该域设置一个4K的cookie,浏览器则分四次将该cookie转发至服务器端——一次针对HTML页面、一次针对每张图片、一次针对 CSS文档再加上一次针对JavaScript文档。
令问题进一步复杂化的原因在于,这个理论上为4K大小的cookie需要从浏览器端传输至服务器端;由于大部分用户使用的是异步互联网连接,即上传速度低于下载速度,因此在HTTP响应头中传输cookie数据一定会造成不必要的带宽占用。
由于上述限制因素的存在,大部分cookies的体积都要远小于4K。谷歌建议每个cookie的实际大小不要超过400字节(或者200个字符), 从而实现最佳性能表现。他们还建议称,在图片、CSS以及JavaScript等来自独特域的静态文件应该禁用cookies机制。
由于cookies机制在本地存储领域存在诸多问题,目前已经出现一系列新兴方案,旨在拨乱反正、保质保量完成任务。近几个月以来,已经有两款方案走上正轨、得到W3C的强烈推荐——它们能够很好、甚至比我们预想中更好地帮助浏览器支持本地存储功能。
目前我们可以从四种主流客户端数据存储机制中做出选择,它们分别是:Web SQL、IndexedDB、Web Storage以及Application Cache。下面我们就逐一对每套方案加以评述,并探讨它们在运作及效果方面的各自特性。
Web SQL: 擅长(但是否有些过时?)数据库创建与执行
Web SQL是一种利用数据库进行数据存储并利用SQL处理检索任务的API。最近,Safari、Chrome以及Opera等知名浏览器纷纷在Web SQL与IndexedDB的竞争之中选择了前者。不过2010年时,SQLite还是惟一一款能够与Web SQL协作的数据库,而W3C出于安装基础较小的理由而停止对这套方案进行支持。
Web SQL的工作机制相当新奇,下面我们就一起来看示例代码。
Web SQL数据库的使用感受与关系类数据库及SQL非常相似。使用这款数据库的第一步在于创建并打开。如果大家不希望额外创建一套数据库,那么完全可以直接开始使用,API本身会自动完成创建工作。
下面我们来看一部分用于数据库创建的代码:
var db = openDatabase('cats', '1.0',
'a catalog of my cats', 2 *1024 * 1024);
按照从左到右的顺序,openDatabase后面的参数依次代表着数据库名称、版本号、文字说明以及预计数据库大小。
数据库创建完成之后,大家就可以着手使用了。在WebSQL数据库上执行SQL与创建事务对象并加以执行一样简单:
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE cats (id unique, name)');
tx.executeSql('INSERT INTO cats (id,name) VALUES (1,"Mr. Jones")');
});
尽管Safari、Chrome、Opera以及Mobile Safari都支持这款API,但自2010年以来Web SQL就没有发生过任何变化,因此它不太可能成为本地存储的新型标准。
Web Storage: 取cookies所长、去cookies所短
Web Storage利用一种简单的方法在用户的浏览器中存储键/值对。但它与cookies之间的相似之处也就仅此而已了。
•Web Storage是一套持久性方案。一旦某个值被存储之后就不会再消失或者终止,除非被应用程序或用户明确删除。
•Web Storage能够处理大量数据。目前浏览器的总体存储区域大小最高为5MB。
•Web Storage无需依赖于服务器,而且不必向服务器端发送数据。当然,大家可以随意实现本地化数据存储并将其与服务器进行异步式同步,但Web Storage的表现始终出色而且在离线与在线状况下都能正常生效。
•Web Storage提供四种主要方法——getItem(键);setItem(键、值);removeItem(键)以及clear()。
最后,Web Storage包含两种完全不同的存储类型:SessionStorage以及LocalStorage。
SessionStorage的作用在于保证被保存在当前浏览器窗口当中的数据仅作用于该窗口。举例来说,当大家使用电子商务类应用程序时,利用SessionStorage来记录用户的购物车信息能够避免误操作所带来的二次购买状况。
下面再来看LocalStorage,它专门负责保存可同时作用于同一浏览器之下各窗口及标签之间的数据。因此,如果大家在Chrome当中打开了三 个关于同一网站的窗口,那么三者能够共同使用同一套LocalStorage容器。相比之下,如果我们打开三个内容彼此独立的网站窗口,那么每一个都将使 用彼此独立的容器。同样,如果大家在不同的浏览器当中打开同一个网站,那么每种浏览器都需要使用属于自己的容器,因此无法共享同一套通用的运行环境。
要设置一套新的键-值对并进行检索,大家可以使用下列JavaScript命令:
//first set firstname equal to Sparky.
localStorage.setItem( "firstname", "Sparky" );
//next, get the value of firstname (hint, it will be Sparky).
localStorage.getItem( "firstname" );
今年夏天,Web Storage API正式获得W3C推荐标准这一殊荣。展望未来,Web Storage完全有可能在一切原本cookies发挥作用的舞台上成为新的处理方案。
但Web Storage能做的还很多。如果大家的数据集并不太大,Web Storage还提供另一种可能是最为简便的处理办法——甚至比cookies更简便——从而顺利搞定浏览器中键-值对的设置与检索工作。
IndexedDB:可搜索且不存在文件大小限制
Indexed Database是一款利用索引化事务性数据库对用户计算机上的数据进行保存与索引的API。IndexedDB带来更快速、更精妙的数据存储与检索效 果,在这方面采用简单键-值对存储机制的cookies以及Web Storage都只能甘拜下风。
与Web Storage一样,IndexedDB API在今年夏天(也就是2013年7月)向Web标准迈进了一大步,成为W3C候选推荐名单中的一员。
与Web Storage相比,IndexedDB带来四项具体提升:
- 能够对索引数据进行高效搜索。
- 数据库能够将多个值保存为一个键,而键-值机制则要求每个键都必须惟一。
- 事务型数据库提供多项针对系统及应用程序故障的保护措施。如果事务流程未能正常完成,则将通过回滚方式进行恢复。
- IndexedDB数据库对数据内容的大小不加限制。在火狐当中,浏览器会要求利用权限将数据库的容量提升到超过50MB,而IndexedDB的实际数据存储量限制直接取决于分卷或者磁盘驱动器本身的容量极限。
除了Safari之外的所有主流浏览器都已经支持IndexedDB。不过由于Safari支持Web SQL,因此我们完全可以利用IndexedDB夹层(或者被称为shim)通过Web SQL实现IndexedDB的功能与语法。
要使用IndexedDB,第一步需要打开一套数据库。
var request = indexedDB.open("myDatabase");
在数据库创建完成之后,大家可以创建一个存储对象(与表格非常类似)并向其中添加数据。假设我们需要向其中添加如下数据:
const petData = [
{ id: "00-01", firstname: "Butters", age: 2, type: "dog" },
{ id: "00-02", firstname: "Sammy", age: 2, type: "dog" }
];
接下来,我们可以创建数据存储机制并通过下列代码加以使用。请注意onupgradeneeded的处理方式:我们在改变数据库结构时需要用到这一方法。
request.onupgradeneeded = function(event) {
var db = event.target.result;
var objectStore = db.createObjectStore("customers", {keyPath: "id"});
for (var i in customerData) {
objectStore.add(customerData[i]);
}
}
IndexedDB擅长于搜索大型数据库集,并能够通过将结构化数据移动至客户端来提高Web应用程序的性能表现。目前它已经非常接近W3C的推荐级别,而且能够被用于全部浏览器平台——尽管具体实施方式有所区别,如前文所述,在Safari中需要借用夹层机制。