介绍 本文是关于客户端存储(client-side storage)的。这是一个通用术语,包含几个独立但相关的 API: Web Storage、Web SQL Database、Indexed Database 和 File Access。每种技术都提供了在用户硬盘上 而非通常存储数据的服务器 存储数据的独特方式。这么做主要基于以下两点理由:(a)使 web app 离线可用; (b)改善性能。对于客户端存储使用情况的详细阐述,请看 HTML5Rocks 上的文章 《“离线”: 这是什么意思?我为何要关心?》。 这些 API 有着类似的作用范围和规则。因此,在去看细节之前,我们先了解他们的共同之处吧。 共同特点基于客户端的存储实际上,“客户端时间存储”的意思是,数据传给了浏览器的存储 API,它将数据存在本地设备中的一块区域,该区域同样也是它存储其他用户特定信息如个人偏好、缓存的地方。除了存储数据,这些 API 可以用来检索数据,且在某些情况下还能执行搜索和批处理操作。 置于沙盒中的所有这四个存储 API 都将数据绑到一个单独的“源”(origin)上。例如,若 http://abc.example.com 保存了一些数据,那以后浏览器就只会允许 http://abc.example.com 获取这些数据。当我们谈论“源”(origin)的时候,这意味着域(domain)必须完全相同,所以 http://example.com 和 http://def.example.com 都不行。端口(port)也必须匹配,因此 http://abc.example.com:123 也是不能访问到 http://abc.example.com (端口默认为80)存储的数据。同样,协议也必须一样(像http vs https 等等)。 空间限制(Quotas)你能想象,如果任何网站都被允许往毫不知情的硬盘里填充以千兆字节计的数据,该有多混乱。因此,浏览器对存储容量施加了限制。若你的应用试图超出限制,浏览器通常会显示一个对话框,让用户确认增加。您可能以为浏览器对单个源(origin)可使用的所有存储都加以同一单独的限制,但多数存储机制都是单独加以限制的。若 Quota API 被采纳,这种情况可能会改变。但就现在来说,把浏览器当作一个二维矩阵,其维度分别是“源”(origin)和“存储”(storage)。例如, “http://abc.example.com” 可能会允许最多存 5MB 的 Web Storage, 25MB 的 Web SQL 数据库,但因用户拒绝访问被禁止使用 Indexed DataBase。 Quota API 将问题放到一起来看,让您查询还有多少可用空间,有多少空间正在使用。 有些情况下,用户也能先看到有多少存储将被使用,例如,当用户在 Chrome 应用商店中安装一个应用时,他们将被提示预先接受其权限,其中包括存储限制。(而该应用的)manifest 中的可能有个值是 “unlimited_storage” (无限制存储)。 数据库处理(Transactions)两个 “数据库” 的存储格式支持数据处理。目的和通常的关系型数据库使用数据处理是一样的:保证数据库完整。数据库处理(Transactions)防止 “竞争条件”(race conditions) 这种情况是:当两个操作序列在同一时间被应用到数据库中, 导致操作结果都无法被预测,而数据库也处于可疑的准确性(dubious accuracy)状态。 同步和异步模式(Synchronous and Asynchronous Modes)多数存储格式都支持同步和异步模式。同步模式是阻塞的,意味着下一行 js 代码执行之前,存储操作会被完整执行。异步模式会使得后面的 js 代码在数据库操作完成之前执行。存储操作会背景环境中执行,当操作完成的时候,应用会以回调函数被调用这种形式接收通知,这个函数须在调用的时候被指定。 应当尽量避免使用同步模式,它虽然看起来比较简单,但操作完成时它会阻塞页面渲染,在某些情况下甚至会冻结整个浏览器。你可能注意到网站乃至是应用出现这种情况,点击一个按钮,结果所有东西都用不了,当你还在想是不是崩溃了?结果一切又突然恢复正常了。 某些 API 没有异步模式,如“localStorage”, 使用这些API时,应当仔细做好性能监测,并随时准备切换到一个异步API,如果它造成了问题。 API 概述及比较Web StorageWeb Storage 是一个叫做 localStorage 的持久对象。可以使用 localStorage.foo = "bar" 保存值,之后可以使用 localStorage.foo 获取到 甚至是浏览器关闭之后重新打开。还可以使用一个叫做 sessionStorage 的对象,工作方式一样,只是当窗口关闭之后会被清除掉。 Web Storage 是 NoSQL 键值对储存(NoSQL key-value store)的一种. Web Storage 的优点
Web Storage 的弱点
Web SQL DatabaseWeb SQL Database 是一个结构化的数据库,具备典型 SQL驱动的关系数据库(SQL-powered relational database)的所有功能和复杂度。Indexed Database 在两者之间。Web SQL Database 有自由形式的密钥值对,有点像 Web Storage,但也有能力从这些值来索引字段,所以搜索速度要快得多。 Web SQL Database 的优点
Web SQL Database 的弱点
Indexed Database (IndexedDB)到目前为止,我们已经看到,Web Storage 和 Web SQL Database 都有各种的优势和弱点。 Indexed Database 产生于这两个早期 API 的经验,可以看作是一种结合两者优点而不招致其劣势得到尝试。 Indexed Database 是一个 “对象存储” (object stores) 的集合,可以直接把对象放进去。这个存储有点像 SQL 表,但在这种情况下,对象的结构没有约束,所以不需要预先定义什么。所以这和 Web Storage 有点像,拥有多个数据库、每个数据库又有多个存储(store)的特点。但不像 Web Storage那样, 还拥有重要的性能优势: 异步接口,可以在存储上创建索引,以提高搜索速度。 IndexedDB 的优点
IndexedDB 的弱点
FileSystem上面的 API 都是适用于文本和结构化数据,但涉及到大文件和二进制内容时,我们需要一些其他的东西。幸运的是,我们现在有了文件系统 API 标准(FileSystem API standard)。它给每个域一个完整的层次化的文件系统,至少在 Chrome 下面,这些都是用户的硬盘上的真正的文件。就单个文件的读写而言, API 建立在现有的 File API之上。 FileSystem(文件系统) API 的有点
FileSystem API 的弱点
来看代码本部分比较不同的 API 如何解决同一个问题。这个例子是一个 “地理情绪”(geo-mood) 签到系统,在那里你可以记录你在时间和地点的情绪。接口可让你在数据库类型之间切换。当然,在现实情况中,这可能显得有点作(contrived),数据库类型肯定比其他的更有意义,文件系统 API 根本不适用于这种应用!但为了演示的目的,如果我们能看到使用不同方式达到同样的结果,这还是有帮助的。还得注意,为了保值可读性,一些代码片段是经过重构的。 现在可以来试试我们的“地理情绪”(geo-mood)应用。 为了让 Demo 更有意思,我们将数据存储单独拿出来,使用标准的面向对象的设计技术(standard object-oriented design techniques)。 UI 逻辑只知道有一个 store;它无需知道 store 是如何实现的,因为每个 store 的方法是一样的。因此 UI 层代码可以称为 store.setup(),store.count() 等等。实际上,我们的 store 有四种实现,每种对应一种存储类型。应用启动的时候,检查 URL 并实例化对应的 store。 为了保持 API 的一致性,所有的方法都是异步的,即它们将结果返回给调用方。Web Storage 的实现甚至也是这样的,其底层实现是本地的。 在下面的演示中,我们将跳过 UI 和定位逻辑,聚焦于存储技术。 建立 Store对 localStorage,我们做个简单的检验看存储是否存在。如果不存在,则新建一个数组,并将其存储在 localStorage 的 checkins(签到) 键下面。首先,我们使用 JSON 对象将结构序列化为字符串,因为大多数浏览器只支持字符串存储。 if (!localStorage.checkins) localStorage.checkins = JSON.stringify([]);
对 Web SQL Database,数据库结构如果不存在的话,我们需要先创建。幸运的是,如果数据库不存在,openDatabase 方法会自动创建数据库;同样,使用 SQL 句 “if not exists” 可以确保新的 checkins 表 如果已经存在的话不会被重写。我们需要预先定义好数据结构,也就是, checkins 表每列的名称和类型。每一行数据代表一次签到。 this.db = openDatabase('geomood', '1.0', 'Geo-Mood Checkins', 8192);
this.db.transaction(function(tx) {
tx.executeSql(
"create table if not exists "
"checkins(id integer primary key asc, time integer, latitude float,"
"longitude float, mood string)",
[], function() {
console.log("siucc");
}
);
});
Indexed Database 启动需要一些工作,因为它需要启用一个数据库版本系统。当我们连接数据库的时候要明确我们需要那个版本,如果当前数据库使用的是之前的版本或者还尚未被创建,会触发 onupgradeneeded 事件,当升级完成后 onsuccess 事件会被触发。如果无需升级,onsuccess 事件马上就会触发。 另外一件事就是创建 “mood” 索引,以便之后能很快地查询到匹配的情绪。 var db;
var version = 1;
window.indexedStore = {};
window.indexedStore.setup = function(handler) { // attempt to open the database
var request = indexedDB.open("geomood", version); // upgrade/create the database if needed
request.onupgradeneeded = function(event) {
var db = request.result;
if (event.oldVersion |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|